Changeset View
Changeset View
Standalone View
Standalone View
head/sys/powerpc/powernv/opal_dev.c
Show All 29 Lines | |||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/bus.h> | #include <sys/bus.h> | ||||
#include <sys/conf.h> | #include <sys/conf.h> | ||||
#include <sys/clock.h> | #include <sys/clock.h> | ||||
#include <sys/cpu.h> | #include <sys/cpu.h> | ||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/kthread.h> | |||||
#include <sys/reboot.h> | #include <sys/reboot.h> | ||||
#include <sys/sysctl.h> | #include <sys/sysctl.h> | ||||
#include <sys/endian.h> | #include <sys/endian.h> | ||||
#include <vm/vm.h> | #include <vm/vm.h> | ||||
#include <vm/pmap.h> | #include <vm/pmap.h> | ||||
#include <dev/ofw/ofw_bus.h> | #include <dev/ofw/ofw_bus.h> | ||||
#include <dev/ofw/ofw_bus_subr.h> | #include <dev/ofw/ofw_bus_subr.h> | ||||
#include <dev/ofw/openfirm.h> | #include <dev/ofw/openfirm.h> | ||||
#include "clock_if.h" | #include "clock_if.h" | ||||
#include "opal.h" | #include "opal.h" | ||||
static int opaldev_probe(device_t); | static int opaldev_probe(device_t); | ||||
static int opaldev_attach(device_t); | static int opaldev_attach(device_t); | ||||
/* clock interface */ | /* clock interface */ | ||||
static int opal_gettime(device_t dev, struct timespec *ts); | static int opal_gettime(device_t dev, struct timespec *ts); | ||||
static int opal_settime(device_t dev, struct timespec *ts); | static int opal_settime(device_t dev, struct timespec *ts); | ||||
/* ofw bus interface */ | /* ofw bus interface */ | ||||
static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev, | static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev, | ||||
device_t child); | device_t child); | ||||
static void opal_shutdown(void *arg, int howto); | static void opal_shutdown(void *arg, int howto); | ||||
static void opal_handle_shutdown_message(void *unused, | |||||
struct opal_msg *msg); | |||||
static void opal_intr(void *); | static void opal_intr(void *); | ||||
static device_method_t opaldev_methods[] = { | static device_method_t opaldev_methods[] = { | ||||
/* Device interface */ | /* Device interface */ | ||||
DEVMETHOD(device_probe, opaldev_probe), | DEVMETHOD(device_probe, opaldev_probe), | ||||
DEVMETHOD(device_attach, opaldev_attach), | DEVMETHOD(device_attach, opaldev_attach), | ||||
/* clock interface */ | /* clock interface */ | ||||
Show All 19 Lines | static driver_t opaldev_driver = { | ||||
opaldev_methods, | opaldev_methods, | ||||
0 | 0 | ||||
}; | }; | ||||
static devclass_t opaldev_devclass; | static devclass_t opaldev_devclass; | ||||
DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, opaldev_devclass, 0, 0); | DRIVER_MODULE(opaldev, ofwbus, opaldev_driver, opaldev_devclass, 0, 0); | ||||
static void opal_heartbeat(void); | |||||
static void opal_handle_messages(void); | |||||
static struct proc *opal_hb_proc; | |||||
static struct kproc_desc opal_heartbeat_kp = { | |||||
"opal_heartbeat", | |||||
opal_heartbeat, | |||||
&opal_hb_proc | |||||
}; | |||||
SYSINIT(opal_heartbeat_setup, SI_SUB_KTHREAD_IDLE, SI_ORDER_ANY, kproc_start, | |||||
&opal_heartbeat_kp); | |||||
static int opal_heartbeat_ms; | |||||
EVENTHANDLER_LIST_DEFINE(OPAL_ASYNC_COMP); | |||||
EVENTHANDLER_LIST_DEFINE(OPAL_EPOW); | |||||
EVENTHANDLER_LIST_DEFINE(OPAL_SHUTDOWN); | |||||
EVENTHANDLER_LIST_DEFINE(OPAL_HMI_EVT); | |||||
EVENTHANDLER_LIST_DEFINE(OPAL_DPO); | |||||
EVENTHANDLER_LIST_DEFINE(OPAL_OCC); | |||||
#define OPAL_SOFT_OFF 0 | |||||
#define OPAL_SOFT_REBOOT 1 | |||||
static void | |||||
opal_heartbeat(void) | |||||
{ | |||||
uint64_t events; | |||||
if (opal_heartbeat_ms == 0) | |||||
kproc_exit(0); | |||||
while (1) { | |||||
events = 0; | |||||
/* Turn the OPAL state crank */ | |||||
opal_call(OPAL_POLL_EVENTS, vtophys(&events)); | |||||
if (events & OPAL_EVENT_MSG_PENDING) | |||||
opal_handle_messages(); | |||||
tsleep(opal_hb_proc, 0, "opal", | |||||
MSEC_2_TICKS(opal_heartbeat_ms)); | |||||
} | |||||
} | |||||
static int | static int | ||||
opaldev_probe(device_t dev) | opaldev_probe(device_t dev) | ||||
{ | { | ||||
phandle_t iparent; | phandle_t iparent; | ||||
pcell_t *irqs; | pcell_t *irqs; | ||||
int i, n_irqs; | int i, n_irqs; | ||||
if (!ofw_bus_is_compatible(dev, "ibm,opal-v3")) | if (!ofw_bus_is_compatible(dev, "ibm,opal-v3")) | ||||
Show All 40 Lines | do { | ||||
rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); | rv = opal_call(OPAL_RTC_READ, vtophys(&junk), vtophys(&junk)); | ||||
if (rv == OPAL_BUSY_EVENT) | if (rv == OPAL_BUSY_EVENT) | ||||
rv = opal_call(OPAL_POLL_EVENTS, 0); | rv = opal_call(OPAL_POLL_EVENTS, 0); | ||||
} while (rv == OPAL_BUSY_EVENT); | } while (rv == OPAL_BUSY_EVENT); | ||||
if (rv == OPAL_SUCCESS) | if (rv == OPAL_SUCCESS) | ||||
clock_register(dev, 2000); | clock_register(dev, 2000); | ||||
EVENTHANDLER_REGISTER(OPAL_SHUTDOWN, opal_handle_shutdown_message, | |||||
NULL, EVENTHANDLER_PRI_ANY); | |||||
EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, | EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, | ||||
SHUTDOWN_PRI_LAST); | SHUTDOWN_PRI_LAST); | ||||
OF_getencprop(ofw_bus_get_node(dev), "ibm,heartbeat-ms", | |||||
&opal_heartbeat_ms, sizeof(opal_heartbeat_ms)); | |||||
/* Bind to interrupts */ | /* Bind to interrupts */ | ||||
for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, | for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, | ||||
RF_ACTIVE)) != NULL; i++) | RF_ACTIVE)) != NULL; i++) | ||||
bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE | | bus_setup_intr(dev, irq, INTR_TYPE_TTY | INTR_MPSAFE | | ||||
INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq), | INTR_ENTROPY, NULL, opal_intr, (void *)rman_get_start(irq), | ||||
NULL); | NULL); | ||||
OF_getencprop(ofw_bus_get_node(dev), "opal-msg-async-num", | OF_getencprop(ofw_bus_get_node(dev), "opal-msg-async-num", | ||||
▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | if (howto & RB_HALT) | ||||
opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); | opal_call(OPAL_CEC_POWER_DOWN, 0 /* Normal power off */); | ||||
else | else | ||||
opal_call(OPAL_CEC_REBOOT); | opal_call(OPAL_CEC_REBOOT); | ||||
opal_call(OPAL_RETURN_CPU); | opal_call(OPAL_RETURN_CPU); | ||||
} | } | ||||
static void | static void | ||||
opal_handle_shutdown_message(void *unused, struct opal_msg *msg) | |||||
{ | |||||
int howto; | |||||
switch (be64toh(msg->params[0])) { | |||||
case OPAL_SOFT_OFF: | |||||
howto = RB_POWEROFF; | |||||
break; | |||||
case OPAL_SOFT_REBOOT: | |||||
howto = RB_REROOT; | |||||
break; | |||||
} | |||||
shutdown_nice(howto); | |||||
} | |||||
static void | |||||
opal_handle_messages(void) | |||||
{ | |||||
static struct opal_msg msg; | |||||
uint64_t rv; | |||||
uint32_t type; | |||||
rv = opal_call(OPAL_GET_MSG, vtophys(&msg), sizeof(msg)); | |||||
if (rv != OPAL_SUCCESS) | |||||
return; | |||||
type = be32toh(msg.msg_type); | |||||
switch (type) { | |||||
case OPAL_MSG_ASYNC_COMP: | |||||
EVENTHANDLER_DIRECT_INVOKE(OPAL_ASYNC_COMP, &msg); | |||||
break; | |||||
case OPAL_MSG_EPOW: | |||||
EVENTHANDLER_DIRECT_INVOKE(OPAL_EPOW, &msg); | |||||
break; | |||||
case OPAL_MSG_SHUTDOWN: | |||||
EVENTHANDLER_DIRECT_INVOKE(OPAL_SHUTDOWN, &msg); | |||||
break; | |||||
case OPAL_MSG_HMI_EVT: | |||||
EVENTHANDLER_DIRECT_INVOKE(OPAL_HMI_EVT, &msg); | |||||
break; | |||||
case OPAL_MSG_DPO: | |||||
EVENTHANDLER_DIRECT_INVOKE(OPAL_DPO, &msg); | |||||
break; | |||||
case OPAL_MSG_OCC: | |||||
EVENTHANDLER_DIRECT_INVOKE(OPAL_OCC, &msg); | |||||
break; | |||||
default: | |||||
printf("Unknown OPAL message type %d\n", type); | |||||
} | |||||
} | |||||
static void | |||||
opal_intr(void *xintr) | opal_intr(void *xintr) | ||||
{ | { | ||||
uint64_t events = 0; | uint64_t events = 0; | ||||
opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr, | opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr, | ||||
vtophys(&events)); | vtophys(&events)); | ||||
/* XXX: do something useful with this information */ | /* Wake up the heartbeat, if it's been setup. */ | ||||
if (events != 0 && opal_hb_proc != NULL) | |||||
wakeup(opal_hb_proc); | |||||
} | } | ||||