Index: head/sys/powerpc/powernv/opal.h =================================================================== --- head/sys/powerpc/powernv/opal.h +++ head/sys/powerpc/powernv/opal.h @@ -31,6 +31,7 @@ #include #include +#include /* Check if OPAL is correctly instantiated. Will try to instantiate it. */ int opal_check(void); @@ -72,6 +73,7 @@ #define OPAL_RETURN_CPU 69 #define OPAL_REINIT_CPUS 70 #define OPAL_CHECK_TOKEN 80 +#define OPAL_GET_MSG 85 #define OPAL_CHECK_ASYNC_COMPLETION 86 #define OPAL_SENSOR_READ 88 #define OPAL_HANDLE_HMI 98 @@ -140,6 +142,19 @@ #define OPAL_TOKEN_ABSENT 0 #define OPAL_TOKEN_PRESENT 1 +#define OPAL_EVENT_OPAL_INTERNAL 0x1 +#define OPAL_EVENT_NVRAM 0x2 +#define OPAL_EVENT_RTC 0x4 +#define OPAL_EVENT_CONSOLE_INPUT 0x8 +#define OPAL_EVENT_CONSOLE_OUTPUT 0x10 +#define OPAL_EVENT_ERROR_LOG_AVAIL 0x20 +#define OPAL_EVENT_ERROR_LOG 0x40 +#define OPAL_EVENT_EPOW 0x80 +#define OPAL_EVENT_LED_STATUS 0x100 +#define OPAL_EVENT_PCI_ERROR 0x200 +#define OPAL_EVENT_DUMP_AVAIL 0x400 +#define OPAL_EVENT_MSG_PENDING 0x800 + #define OPAL_HMI_FLAGS_TB_RESYNC (1ull << 0) #define OPAL_HMI_FLAGS_DEC_LOST (1ull << 1) #define OPAL_HMI_FLAGS_HDEC_LOST (1ull << 2) @@ -188,4 +203,17 @@ void opal_free_async_token(int); int opal_wait_completion(void *, uint64_t, uint64_t); +typedef void (*opal_msg_handler_fn)(void *, struct opal_msg *); +EVENTHANDLER_DECLARE(OPAL_ASYNC_COMP, opal_msg_handler_fn); +EVENTHANDLER_DECLARE(OPAL_EPOW, opal_msg_handler_fn); +EVENTHANDLER_DECLARE(OPAL_SHUTDOWN, opal_msg_handler_fn); +EVENTHANDLER_DECLARE(OPAL_HMI_EVT, opal_msg_handler_fn); +EVENTHANDLER_DECLARE(OPAL_DPO, opal_msg_handler_fn); +EVENTHANDLER_DECLARE(OPAL_OCC, opal_msg_handler_fn); +EVENTHANDLER_LIST_DECLARE(OPAL_ASYNC_COMP); +EVENTHANDLER_LIST_DECLARE(OPAL_EPOW); +EVENTHANDLER_LIST_DECLARE(OPAL_SHUTDOWN); +EVENTHANDLER_LIST_DECLARE(OPAL_HMI_EVT); +EVENTHANDLER_LIST_DECLARE(OPAL_DPO); +EVENTHANDLER_LIST_DECLARE(OPAL_OCC); #endif Index: head/sys/powerpc/powernv/opal_dev.c =================================================================== --- head/sys/powerpc/powernv/opal_dev.c +++ head/sys/powerpc/powernv/opal_dev.c @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -59,6 +60,8 @@ device_t child); 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 device_method_t opaldev_methods[] = { @@ -94,6 +97,49 @@ 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 opaldev_probe(device_t dev) { @@ -150,9 +196,13 @@ if (rv == OPAL_SUCCESS) clock_register(dev, 2000); + EVENTHANDLER_REGISTER(OPAL_SHUTDOWN, opal_handle_shutdown_message, + NULL, EVENTHANDLER_PRI_ANY); EVENTHANDLER_REGISTER(shutdown_final, opal_shutdown, NULL, SHUTDOWN_PRI_LAST); + OF_getencprop(ofw_bus_get_node(dev), "ibm,heartbeat-ms", + &opal_heartbeat_ms, sizeof(opal_heartbeat_ms)); /* Bind to interrupts */ for (i = 0; (irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &i, RF_ACTIVE)) != NULL; i++) @@ -306,13 +356,68 @@ } 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) { uint64_t events = 0; opal_call(OPAL_HANDLE_INTERRUPT, (uint32_t)(uint64_t)xintr, 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); }