diff options
author | marius <marius@FreeBSD.org> | 2013-03-02 00:37:31 +0000 |
---|---|---|
committer | marius <marius@FreeBSD.org> | 2013-03-02 00:37:31 +0000 |
commit | 2774e0404e6c83cc801bf5edbedcb8ceb5ee1e16 (patch) | |
tree | 47c03ab3e147cee5fe05e38499fbda5d9143f056 /sys/sparc64 | |
parent | 24853370053f911de81d645be20801b842a3dda9 (diff) | |
download | FreeBSD-src-2774e0404e6c83cc801bf5edbedcb8ceb5ee1e16.zip FreeBSD-src-2774e0404e6c83cc801bf5edbedcb8ceb5ee1e16.tar.gz |
- While Netra X1 generally show no ill effects when registering a power
fail interrupt handler, there seems to be either a broken batch of them
or a tendency to develop a defect which causes this interrupt to fire
inadvertedly. Given that apart from this problem these machines work
just fine, add a tunable allowing the setup of the power fail interrupt
to be disabled.
While at it, remove the DEBUGGER_ON_POWERFAIL compile time option and
make that behavior also selectable via the newly added tunable.
- Apparently, it's no longer a problem to call shutdown_nice(9) from within
an interrupt filter (some other drivers in the tree do the same). So
change the power fail interrupt from an handler in order to simplify the
code and get rid of a !INTR_MPSAFE handler.
- Use NULL instead of 0 for pointers.
MFC after: 1 week
Diffstat (limited to 'sys/sparc64')
-rw-r--r-- | sys/sparc64/pci/psycho.c | 71 |
1 files changed, 44 insertions, 27 deletions
diff --git a/sys/sparc64/pci/psycho.c b/sys/sparc64/pci/psycho.c index a44af7c..8f4f23e 100644 --- a/sys/sparc64/pci/psycho.c +++ b/sys/sparc64/pci/psycho.c @@ -54,6 +54,7 @@ __FBSDID("$FreeBSD$"); #include <sys/pcpu.h> #include <sys/reboot.h> #include <sys/rman.h> +#include <sys/sysctl.h> #include <dev/ofw/ofw_bus.h> #include <dev/ofw/ofw_pci.h> @@ -80,7 +81,7 @@ static const struct psycho_desc *psycho_find_desc(const struct psycho_desc *, const char *); static const struct psycho_desc *psycho_get_desc(device_t); static void psycho_set_intr(struct psycho_softc *, u_int, bus_addr_t, - driver_filter_t, driver_intr_t); + driver_filter_t); static int psycho_find_intrmap(struct psycho_softc *, u_int, bus_addr_t *, bus_addr_t *, u_long *); static void sabre_dmamap_sync(bus_dma_tag_t dt, bus_dmamap_t map, @@ -94,8 +95,9 @@ static void psycho_intr_clear(void *); static driver_filter_t psycho_ue; static driver_filter_t psycho_ce; static driver_filter_t psycho_pci_bus; -static driver_filter_t psycho_powerfail; -static driver_intr_t psycho_overtemp; +static driver_filter_t psycho_powerdebug; +static driver_filter_t psycho_powerdown; +static driver_filter_t psycho_overtemp; #ifdef PSYCHO_MAP_WAKEUP static driver_filter_t psycho_wakeup; #endif @@ -159,9 +161,16 @@ static devclass_t psycho_devclass; DEFINE_CLASS_0(pcib, psycho_driver, psycho_methods, sizeof(struct psycho_softc)); -EARLY_DRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, 0, 0, +EARLY_DRIVER_MODULE(psycho, nexus, psycho_driver, psycho_devclass, NULL, NULL, BUS_PASS_BUS); +static SYSCTL_NODE(_hw, OID_AUTO, psycho, CTLFLAG_RD, 0, "psycho parameters"); + +static u_int psycho_powerfail = 1; +TUNABLE_INT("hw.psycho.powerfail", &psycho_powerfail); +SYSCTL_UINT(_hw_psycho, OID_AUTO, powerfail, CTLFLAG_RDTUN, &psycho_powerfail, + 0, "powerfail action (0: none, 1: shutdown (default), 2: debugger)"); + static SLIST_HEAD(, psycho_softc) psycho_softcs = SLIST_HEAD_INITIALIZER(psycho_softcs); @@ -610,15 +619,20 @@ psycho_attach(device_t dev) * XXX Not all controllers have these, but installing them * is better than trying to sort through this mess. */ - psycho_set_intr(sc, 1, PSR_UE_INT_MAP, psycho_ue, NULL); - psycho_set_intr(sc, 2, PSR_CE_INT_MAP, psycho_ce, NULL); -#ifdef DEBUGGER_ON_POWERFAIL - psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, psycho_powerfail, - NULL); -#else - psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, NULL, - (driver_intr_t *)psycho_powerfail); -#endif + psycho_set_intr(sc, 1, PSR_UE_INT_MAP, psycho_ue); + psycho_set_intr(sc, 2, PSR_CE_INT_MAP, psycho_ce); + switch (psycho_powerfail) { + case 0: + break; + case 2: + psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, + psycho_powerdebug); + break; + default: + psycho_set_intr(sc, 3, PSR_POWER_INT_MAP, + psycho_powerdown); + break; + } if (sc->sc_mode == PSYCHO_MODE_PSYCHO) { /* * Hummingbirds/Sabres do not have the following two @@ -630,14 +644,14 @@ psycho_attach(device_t dev) * over-temperature interrupt. */ psycho_set_intr(sc, 4, PSR_SPARE_INT_MAP, - NULL, psycho_overtemp); + psycho_overtemp); #ifdef PSYCHO_MAP_WAKEUP /* * psycho_wakeup() doesn't do anything useful right * now. */ psycho_set_intr(sc, 5, PSR_PWRMGT_INT_MAP, - psycho_wakeup, NULL); + psycho_wakeup); #endif /* PSYCHO_MAP_WAKEUP */ } } @@ -647,7 +661,7 @@ psycho_attach(device_t dev) * interrupt but they are also only used for PCI bus A. */ psycho_set_intr(sc, 0, sc->sc_half == 0 ? PSR_PCIAERR_INT_MAP : - PSR_PCIBERR_INT_MAP, psycho_pci_bus, NULL); + PSR_PCIBERR_INT_MAP, psycho_pci_bus); /* * Set the latency timer register as this isn't always done by the @@ -687,7 +701,7 @@ psycho_attach(device_t dev) static void psycho_set_intr(struct psycho_softc *sc, u_int index, bus_addr_t intrmap, - driver_filter_t filt, driver_intr_t intr) + driver_filter_t handler) { u_long vec; int rid; @@ -708,7 +722,7 @@ psycho_set_intr(struct psycho_softc *sc, u_int index, bus_addr_t intrmap, INTVEC(PSYCHO_READ8(sc, intrmap)) != vec || intr_vectors[vec].iv_ic != &psycho_ic || bus_setup_intr(sc->sc_dev, sc->sc_irq_res[index], - INTR_TYPE_MISC | INTR_BRIDGE, filt, intr, sc, + INTR_TYPE_MISC | INTR_BRIDGE, handler, NULL, sc, &sc->sc_ihand[index]) != 0) panic("%s: failed to set up interrupt %d", __func__, index); } @@ -837,13 +851,16 @@ psycho_pci_bus(void *arg) } static int -psycho_powerfail(void *arg) +psycho_powerdebug(void *arg __unused) { -#ifdef DEBUGGER_ON_POWERFAIL - struct psycho_softc *sc = arg; kdb_enter(KDB_WHY_POWERFAIL, "powerfail"); -#else + return (FILTER_HANDLED); +} + +static int +psycho_powerdown(void *arg __unused) +{ static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ @@ -851,22 +868,22 @@ psycho_powerfail(void *arg) return (FILTER_HANDLED); shutdown++; printf("Power Failure Detected: Shutting down NOW.\n"); - shutdown_nice(0); -#endif + shutdown_nice(RB_POWEROFF); return (FILTER_HANDLED); } -static void -psycho_overtemp(void *arg) +static int +psycho_overtemp(void *arg __unused) { static int shutdown; /* As the interrupt is cleared we may be called multiple times. */ if (shutdown != 0) - return; + return (FILTER_HANDLED); shutdown++; printf("DANGER: OVER TEMPERATURE detected.\nShutting down NOW.\n"); shutdown_nice(RB_POWEROFF); + return (FILTER_HANDLED); } #ifdef PSYCHO_MAP_WAKEUP |