- 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
This commit is contained in:
Marius Strobl 2013-03-02 00:37:31 +00:00
parent d6f122f4fb
commit 7e026d15d5
2 changed files with 44 additions and 28 deletions

View File

@ -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

View File

@ -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