mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-15 12:54:27 +00:00
powerpc/powernv: Add OPAL heartbeat thread
Summary: OPAL needs to be kicked periodically in order for the firmware to make progress on its tasks. To do so, create a heartbeat thread to perform this task every N milliseconds, defined by the device tree. This task is also a central location to handle all messages received from OPAL. Reviewed By: luporl Differential Revision: https://reviews.freebsd.org/D19743
This commit is contained in:
parent
8ac5aef8f3
commit
911a92603e
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=345789
|
@ -31,6 +31,7 @@
|
|||
|
||||
#include <sys/cdefs.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/eventhandler.h>
|
||||
|
||||
/* Check if OPAL is correctly instantiated. Will try to instantiate it. */
|
||||
int opal_check(void);
|
||||
|
@ -72,6 +73,7 @@ int opal_call(uint64_t token, ...);
|
|||
#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 @@ int opal_call(uint64_t token, ...);
|
|||
#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 @@ int opal_alloc_async_token(void);
|
|||
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
|
||||
|
|
|
@ -35,6 +35,7 @@ __FBSDID("$FreeBSD$");
|
|||
#include <sys/clock.h>
|
||||
#include <sys/cpu.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/kthread.h>
|
||||
#include <sys/reboot.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/endian.h>
|
||||
|
@ -59,6 +60,8 @@ static const struct ofw_bus_devinfo *opaldev_get_devinfo(device_t dev,
|
|||
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 @@ static devclass_t opaldev_devclass;
|
|||
|
||||
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 @@ opaldev_attach(device_t dev)
|
|||
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++)
|
||||
|
@ -305,6 +355,59 @@ opal_shutdown(void *arg, int howto)
|
|||
opal_call(OPAL_RETURN_CPU);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -312,7 +415,9 @@ opal_intr(void *xintr)
|
|||
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue