Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 2 Apr 2019 04:00:01 +0000 (UTC)
From:      Justin Hibbits <jhibbits@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r345789 - head/sys/powerpc/powernv
Message-ID:  <201904020400.x32401O8076808@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jhibbits
Date: Tue Apr  2 04:00:01 2019
New Revision: 345789
URL: https://svnweb.freebsd.org/changeset/base/345789

Log:
  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

Modified:
  head/sys/powerpc/powernv/opal.h
  head/sys/powerpc/powernv/opal_dev.c

Modified: head/sys/powerpc/powernv/opal.h
==============================================================================
--- head/sys/powerpc/powernv/opal.h	Mon Apr  1 23:37:21 2019	(r345788)
+++ head/sys/powerpc/powernv/opal.h	Tue Apr  2 04:00:01 2019	(r345789)
@@ -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

Modified: head/sys/powerpc/powernv/opal_dev.c
==============================================================================
--- head/sys/powerpc/powernv/opal_dev.c	Mon Apr  1 23:37:21 2019	(r345788)
+++ head/sys/powerpc/powernv/opal_dev.c	Tue Apr  2 04:00:01 2019	(r345789)
@@ -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_devin
     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++)
@@ -306,13 +356,68 @@ opal_shutdown(void *arg, int howto)
 }
 
 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);
 
 }
 



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201904020400.x32401O8076808>