summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormarius <marius@FreeBSD.org>2013-03-02 00:37:31 +0000
committermarius <marius@FreeBSD.org>2013-03-02 00:37:31 +0000
commit2774e0404e6c83cc801bf5edbedcb8ceb5ee1e16 (patch)
tree47c03ab3e147cee5fe05e38499fbda5d9143f056
parent24853370053f911de81d645be20801b842a3dda9 (diff)
downloadFreeBSD-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
-rw-r--r--sys/conf/options.sparc641
-rw-r--r--sys/sparc64/pci/psycho.c71
2 files changed, 44 insertions, 28 deletions
diff --git a/sys/conf/options.sparc64 b/sys/conf/options.sparc64
index bc6af5a..883db16 100644
--- a/sys/conf/options.sparc64
+++ b/sys/conf/options.sparc64
@@ -23,7 +23,6 @@ PSM_DEBUG opt_psm.h
PSM_HOOKRESUME opt_psm.h
PSM_RESETAFTERSUSPEND opt_psm.h
-DEBUGGER_ON_POWERFAIL opt_psycho.h
PSYCHO_DEBUG opt_psycho.h
SCHIZO_DEBUG opt_schizo.h
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
OpenPOWER on IntegriCloud