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);
 
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to