<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><span></span></div><div><div><br></div><div><br>On 30-Apr-2015, at 11:37, Vipin K Parashar <<a href="mailto:vipin@linux.vnet.ibm.com">vipin@linux.vnet.ibm.com</a>> wrote:<br><br></div><blockquote type="cite"><div><span>This patch adds support for FSP EPOW (Early Power Off Warning) and</span><br><span>DPO (Delayed Power Off) events support for PowerNV platform.  EPOW events</span><br><span>are generated by SPCN/FSP due to various critical system conditions that</span><br><span>need system shutdown.  Few examples of these conditions are high ambient</span><br><span>temperature or system running on UPS power with low UPS battery. DPO event</span><br><span>is generated in response to admin initiated system shutdown request.</span><br><span>    This patch enables host kernel on PowerNV platform to handle OPAL</span><br><span>notifications for these events and initiate system poweroff. Since EPOW</span><br><span>notifications are sent in advance of impending shutdown event and thus this</span><br><span>patch also adds functionality to wait for EPOW condition to return to</span><br><span>normal.  If EPOW condition doesn't return to normal in estimated time it</span><br><span>proceeds with graceful system shutdown. System admin can also add host</span><br><span>userspace scripts to perform any specific actions like graceful guest</span><br><span>shutdown upon system poweroff.</span><br><span></span><br><span>Signed-off-by: Vipin K Parashar <<a href="mailto:vipin@linux.vnet.ibm.com">vipin@linux.vnet.ibm.com</a>></span><br><span>---</span><br><span> arch/powerpc/include/asm/opal-api.h                |  30 ++</span><br><span> arch/powerpc/include/asm/opal.h                    |   3 +-</span><br><span> arch/powerpc/platforms/powernv/Makefile            |   1 +</span><br><span> .../platforms/powernv/opal-poweroff-events.c       | 358 +++++++++++++++++++++</span><br><span> arch/powerpc/platforms/powernv/opal-wrappers.S     |   1 +</span><br><span> 5 files changed, 392 insertions(+), 1 deletion(-)</span><br><span> create mode 100644 arch/powerpc/platforms/powernv/opal-poweroff-events.c</span><br><span></span><br><span>diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h</span><br><span>index 0321a90..03b3cef 100644</span><br><span>--- a/arch/powerpc/include/asm/opal-api.h</span><br><span>+++ b/arch/powerpc/include/asm/opal-api.h</span><br><span>@@ -730,6 +730,36 @@ struct opal_i2c_request {</span><br><span>     __be64 buffer_ra;        /* Buffer real address */</span><br><span> };</span><br><span></span><br><span>+/*</span><br><span>+ * EPOW status sharing (OPAL and the host)</span><br><span>+ *</span><br><span>+ * The host will pass on OPAL, a buffer of length OPAL_EPOW_MAX_CLASSES</span><br><span>+ * to fetch system wide EPOW status. Each element in the returned buffer</span><br><span>+ * will contain bitwise EPOW status for each EPOW sub class.</span><br><span>+ */</span><br><span>+</span><br><span>+/* EPOW types */</span><br><span>+enum OpalEpow {</span><br><span>+    OPAL_EPOW_POWER         = 0,    /* Power EPOW */</span><br><span>+    OPAL_EPOW_TEMP          = 1,    /* Temperature EPOW */</span><br><span>+    OPAL_EPOW_COOLING       = 2,    /* Cooling EPOW */</span><br><span>+    OPAL_MAX_EPOW_CLASSES   = 3,    /* Max EPOW categories */</span><br><span>+};</span><br><span>+</span><br><span>+/* Power EPOW events */</span><br><span>+enum OpalEpowPower {</span><br><span>+    OPAL_EPOW_POWER_UPS     = 0x1, /* System on UPS power */</span><br><span>+    OPAL_EPOW_POWER_UPS_LOW = 0x2, /* System on UPS power with low battery*/</span><br><span>+};</span><br><span>+</span><br><span>+/* Temperature EPOW events */</span><br><span>+enum OpalEpowTemp {</span><br><span>+    OPAL_EPOW_TEMP_HIGH_AMB = 0x1, /* High ambient temperature */</span><br><span>+    OPAL_EPOW_TEMP_CRIT_AMB = 0x2, /* Critical ambient temperature */</span><br><span>+    OPAL_EPOW_TEMP_HIGH_INT = 0x4, /* High internal temperature */</span><br><span>+    OPAL_EPOW_TEMP_CRIT_INT = 0x8, /* Critical internal temperature */</span><br><span>+};</span><br><span>+</span><br><span> #endif /* __ASSEMBLY__ */</span><br><span></span><br><span> #endif /* __OPAL_API_H */</span><br><span>diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h</span><br><span>index 042af1a..0777864 100644</span><br><span>--- a/arch/powerpc/include/asm/opal.h</span><br><span>+++ b/arch/powerpc/include/asm/opal.h</span><br><span>@@ -141,7 +141,6 @@ int64_t opal_pci_fence_phb(uint64_t phb_id);</span><br><span> int64_t opal_pci_reinit(uint64_t phb_id, uint64_t reinit_scope, uint64_t data);</span><br><span> int64_t opal_pci_mask_pe_error(uint64_t phb_id, uint16_t pe_number, uint8_t error_type, uint8_t mask_action);</span><br><span> int64_t opal_set_slot_led_status(uint64_t phb_id, uint64_t slot_id, uint8_t led_type, uint8_t led_action);</span><br><span>-int64_t opal_get_epow_status(__be64 *status);</span><br><span> int64_t opal_set_system_attention_led(uint8_t led_action);</span><br><span> int64_t opal_pci_next_error(uint64_t phb_id, __be64 *first_frozen_pe,</span><br><span>                 __be16 *pci_error_type, __be16 *severity);</span><br><span>@@ -200,6 +199,8 @@ int64_t opal_flash_write(uint64_t id, uint64_t offset, uint64_t buf,</span><br><span>         uint64_t size, uint64_t token);</span><br><span> int64_t opal_flash_erase(uint64_t id, uint64_t offset, uint64_t size,</span><br><span>         uint64_t token);</span><br><span>+int32_t opal_get_epow_status(__be32 *status, __be32 *num_classes);</span><br><span>+int32_t opal_get_dpo_status(__be32 *timeout);</span><br><span></span><br><span> /* Internal functions */</span><br><span> extern int early_init_dt_scan_opal(unsigned long node, const char *uname,</span><br><span>diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile</span><br><span>index 33e44f3..b817bdb 100644</span><br><span>--- a/arch/powerpc/platforms/powernv/Makefile</span><br><span>+++ b/arch/powerpc/platforms/powernv/Makefile</span><br><span>@@ -2,6 +2,7 @@ obj-y            += setup.o opal-wrappers.o opal.o opal-async.o</span><br><span> obj-y            += opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o</span><br><span> obj-y            += rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o</span><br><span> obj-y            += opal-msglog.o opal-hmi.o opal-power.o</span><br><span>+obj-y            += opal-poweroff-events.o</span><br><span></span><br><span> obj-$(CONFIG_SMP)    += smp.o subcore.o subcore-asm.o</span><br><span> obj-$(CONFIG_PCI)    += pci.o pci-p5ioc2.o pci-ioda.o</span><br><span>diff --git a/arch/powerpc/platforms/powernv/opal-poweroff-events.c b/arch/powerpc/platforms/powernv/opal-poweroff-events.c</span><br><span>new file mode 100644</span><br><span>index 0000000..9b169e2</span><br><span>--- /dev/null</span><br><span>+++ b/arch/powerpc/platforms/powernv/opal-poweroff-events.c</span><br><span>@@ -0,0 +1,358 @@</span><br></div></blockquote>Instead of creating a new file can you merge this functionality with existing code in opal-power.c. It seems to be doing work similar to what you are doing in this code.<br><blockquote type="cite"><div><span>+/*</span><br><span>+ * PowerNV poweroff events support</span><br><span>+ *</span><br><span>+ * Copyright 2015 IBM Corp.</span><br><span>+ *</span><br><span>+ * This program is free software; you can redistribute it and/or</span><br><span>+ * modify it under the terms of the GNU General Public License</span><br><span>+ * as published by the Free Software Foundation; either version</span><br><span>+ * 2 of the License, or (at your option) any later version.</span><br><span>+ */</span><br><span>+</span><br><span>+#define pr_fmt(fmt)    "POWEROFF_EVENT: "    fmt</span><br><span>+</span><br><span>+#include <linux/kernel.h></span><br><span>+#include <linux/spinlock.h></span><br><span>+#include <linux/timer.h></span><br><span>+#include <linux/reboot.h></span><br><span>+#include <asm/opal.h></span><br><span>+#include <asm/machdep.h></span><br><span>+</span><br><span>+/* System EPOW status */</span><br><span>+u32 epow_status[OPAL_MAX_EPOW_CLASSES];</span><br><span>+int num_epow_classes;</span><br><span>+</span><br><span>+/* EPOW event timer and corresponding locks */</span><br><span>+static struct timer_list epow_timer;</span><br><span>+static DEFINE_SPINLOCK(epow_timer_spinlock);</span><br><span>+</span><br><span>+/* EPOW, DPO event status values */</span><br><span>+#define    DPO_DETECTED    1</span><br><span>+#define    EPOW_DETECTED    1</span><br></div></blockquote>Instead of macros for this can you simply return a bool from corresponding functions.<br><blockquote type="cite"><div><span>+</span><br><span>+/* EPOW events supported */</span><br><span>+#define EPOW_POWER_UPS          0</span><br><span>+#define EPOW_POWER_UPS_LOW      1</span><br><span>+#define EPOW_TEMP_HIGH_AMB      2</span><br><span>+#define EPOW_TEMP_CRIT_AMB      3</span><br><span>+#define EPOW_TEMP_HIGH_INT      4</span><br><span>+#define EPOW_TEMP_CRIT_INT      5</span><br><span>+#define MAX_EPOW_EVENTS        6</span><br><span>+</span><br><span>+/* EPOW events description */</span><br><span>+static const char * const epow_events_map[] = {</span><br><span>+    [EPOW_POWER_UPS]    = "UPS",</span><br><span>+    [EPOW_POWER_UPS_LOW]    = "UPS-low",</span><br><span>+    [EPOW_TEMP_HIGH_AMB]    = "high-ambient-temp",</span><br><span>+    [EPOW_TEMP_CRIT_AMB]    = "crit-ambient-temp",</span><br><span>+    [EPOW_TEMP_HIGH_INT]    = "high-internal-temp",</span><br><span>+    [EPOW_TEMP_CRIT_INT]    = "crit-internal-temp",</span><br><span>+};</span><br><span>+</span><br><span>+/* EPOW events timeout values */</span><br><span>+static int epow_timeout[MAX_EPOW_EVENTS];</span><br><span>+</span><br><span>+/*</span><br><span>+ * TODO: Export various event timeout values via device tree.</span><br><span>+ *  Zero timeout value for any event suggests that it needs</span><br><span>+ *  immediate shutdown.</span><br><span>+ */</span><br><span>+#define TIMEOUT_EPOW_POWER_UPS        450</span><br><span>+#define TIMEOUT_EPOW_TEMP_HIGH_AMB    450</span><br><span>+</span><br><span>+/*</span><br><span>+ * Get various EPOW event timeouts.</span><br><span>+ * TODO: For now hardcoding timeout values but they need to be</span><br><span>+ * obtained via firmware device-tree.</span><br><span>+ */</span><br><span>+void get_epow_timeouts(void)</span><br><span>+{</span><br><span>+    epow_timeout[EPOW_POWER_UPS] = TIMEOUT_EPOW_POWER_UPS;</span><br><span>+    epow_timeout[EPOW_TEMP_HIGH_AMB] = TIMEOUT_EPOW_TEMP_HIGH_AMB;</span><br><span>+}</span><br><span>+</span><br></div></blockquote>Instead of having a separate function function for initialising the array you can use array initialisers.<br><blockquote type="cite"><div><span>+/* EPOW poweroff function. */</span><br><span>+static void epow_poweroff(unsigned long event)</span><br><span>+{</span><br><span>+    pr_info("Powering off system due to %s EPOW event\n",</span><br><span>+                epow_events_map[event]);</span><br><span>+    orderly_poweroff(true);</span><br><span>+}</span><br><span>+</span><br><span>+/* Start EPOW poweroff timer */</span><br><span>+static void start_epow_timer(unsigned long event, int32_t timeout)</span><br><span>+{</span><br><span>+    unsigned long flags;</span><br><span>+</span><br><span>+    spin_lock_irqsave(&epow_timer_spinlock, flags);</span><br><span>+    /* Check for already running epow poweroff timer */</span><br><span>+    if (timer_pending(&epow_timer)) {</span><br><span>+        /* Timer for same event */</span><br><span>+        if (epow_timer.data == event) {</span><br><span>+            spin_unlock_irqrestore(&epow_timer_spinlock, flags);</span><br><span>+            return;</span><br><span>+        }</span><br><span>+</span><br><span>+        /* Timer with early poweroff timeout */</span><br><span>+        if (epow_timer.expires < (jiffies + timeout * HZ)) {</span><br><span>+            event = epow_timer.data;</span><br><span>+            spin_unlock_irqrestore(&epow_timer_spinlock, flags);</span><br><span>+            pr_info("Poweroff already scheduled for %s EPOW event "</span><br><span>+                    "with earlier timeout.\n",</span><br><span>+                    epow_events_map[event]);</span><br><span>+            return;</span><br><span>+        }</span><br><span>+    }</span><br><span>+</span><br><span>+    /* Start a new timer/modify existing timer with new timeout value */</span><br><span>+    epow_timer.data = event;</span><br><span>+    mod_timer(&epow_timer, jiffies + timeout  * HZ);</span><br><span>+    spin_unlock_irqrestore(&epow_timer_spinlock, flags);</span><br><span>+    pr_info("Scheduled system poweroff due to %s EPOW event "</span><br><span>+            "after %d seconds\n", epow_events_map[event], timeout);</span><br><span>+}</span><br><span>+</span><br><span>+/* Stop poweroff timer */</span><br><span>+static void stop_epow_timer(void)</span><br><span>+{</span><br><span>+    int rc;</span><br><span>+    unsigned long flags;</span><br><span>+</span><br><span>+    spin_lock_irqsave(&epow_timer_spinlock, flags);</span><br><span>+    rc = del_timer(&epow_timer);</span><br><span>+    spin_unlock_irqrestore(&epow_timer_spinlock, flags);</span><br><span>+</span><br><span>+    if (rc)</span><br><span>+        pr_info("Poweroff timer deactivated\n");</span><br><span>+}</span><br><span>+</span><br><span>+/* Get DPO status */</span><br><span>+static int get_dpo_status(int32_t *dpo_timeout)</span><br><span>+{</span><br><span>+    int rc;</span><br><span>+    __be32 opal_dpo_timeout;</span><br><span>+</span><br><span>+    rc = opal_get_dpo_status(&opal_dpo_timeout);</span><br><span>+    if (rc == OPAL_WRONG_STATE) {</span><br><span>+        *dpo_timeout = 0;</span><br><span>+        return 0;</span><br><span>+    }</span><br><span>+</span><br><span>+    *dpo_timeout = be32_to_cpu(opal_dpo_timeout);</span><br><span>+    return DPO_DETECTED;</span><br><span>+}</span><br><span>+</span><br><span>+/* Process DPO event */</span><br><span>+void process_dpo(void)</span><br><span>+{</span><br><span>+    pr_info("Powering off system due to poweroff request.\n");</span><br><span>+    orderly_poweroff(true);</span><br><span>+}</span><br></div></blockquote>Function too small and can be combined with function opal_dpo_event.<br><blockquote type="cite"><div><span>+</span><br><span>+/* Get EPOW status */</span><br><span>+static int get_epow_status(void)</span><br><span>+{</span><br><span>+    int i;</span><br><span>+    bool epow_detected = false;</span><br><span>+</span><br><span>+    __be32 opal_epow_status[OPAL_MAX_EPOW_CLASSES];</span><br><span>+    __be32 opal_epow_classes;</span><br><span>+</span><br><span>+    opal_epow_classes = cpu_to_be32(OPAL_MAX_EPOW_CLASSES);</span><br><span>+    for (i = 0; i < OPAL_MAX_EPOW_CLASSES; i++)</span><br><span>+        opal_epow_status[i] = cpu_to_be32(0);</span><br></div></blockquote>0 is represented same in be or le. So instead use static initialiser for the array.<br><blockquote type="cite"><div><span>+</span><br><span>+    /* Get EPOW events information from OPAL */</span><br><span>+    opal_get_epow_status(opal_epow_status, &opal_epow_classes);</span><br></div></blockquote>Since you get the number of classes copied to the array back from opal, you may not need to initialise it to zero in the loop above.<br><blockquote type="cite"><div><span>+</span><br><span>+    /* Copy EPOW status */</span><br><span>+    </span><font color="#000000"><span style="background-color: rgba(255, 255, 255, 0);"> memset(epow_status, 0, sizeof(epow_status[0] * OPAL_MAX_EPOW_CLASSES);</span></font></div></blockquote>Simple <span style="background-color: rgba(255, 255, 255, 0);">memset(epow_status, 0, sizeof(epow_status)) should have the same effect</span><br><blockquote type="cite"><div><span>+    num_epos_classes = be32_to_cpu(opal_epow_classes);</span><br><span>+    for (i = 0; i < num_epow_classes; i++) {</span><br><span>+        epow_status[i] = be32_to_cpu(opal_epow_status[i]);</span><br><span>+        if (epow_status[i])</span><br><span>+            epow_detected = true;</span><br><span>+    }</span><br><span>+</span><br><span>+    pr_info("EPOW classes supported OPAL = %d, Host = %d "</span><br><span>+            "EPOW Status = 0x%x, 0x%x, 0x%x\n",</span><br><span>+            num_epow_classes, OPAL_MAX_EPOW_CLASSES,</span><br><span>+            epow_status[0], epow_status[1], epow_status[2]);</span><br><span>+</span><br><span>+    if (epow_detected)</span><br><span>+        return EPOW_DETECTED;</span><br><span>+</span><br><span>+    return 0;</span><br><span>+}</span><br><span>+</span><br><span>+/* Process EPOW information */</span><br><span>+void process_epow(void)</span><br><span>+{</span><br><span>+    int i, timeout = 0, event = -1;</span><br><span>+    bool epow_normal = false;</span><br><span>+</span><br><span>+    /* Check for EPOW return to normal state */</span><br><span>+    for (i = 0; i < OPAL_MAX_EPOW_CLASSES; i++) {</span><br><span>+        if (epow_status[i])</span><br><span>+            break;</span><br><span>+    }</span><br></div></blockquote>This is the same check you do in func get_epow_status. Instead refactor the code to do this check only once.<br><blockquote type="cite"><div><span>+</span><br><span>+    if (i == OPAL_MAX_EPOW_CLASSES)</span><br><span>+        epow_normal = true;</span><br><span>+</span><br><span>+    /* Cancel any pending shutdown timer due to EPOW normal state.*/</span><br><span>+    if (epow_normal) {</span><br><span>+        stop_epow_timer(); </span><br><span>+        return;</span><br><span>+    }</span><br></div></blockquote>Can merge the two if conditions above to eliminate variable epow_normal.<br><blockquote type="cite"><div><span>+</span><br><span>+    /* Determine EPOW events and poweroff timeouts */</span><br><span>+    if (epow_status[OPAL_EPOW_POWER] & OPAL_EPOW_POWER_UPS) {</span><br><span>+        pr_info("EPOW due to system running on UPS power\n");</span><br><span>+        event = EPOW_POWER_UPS;</span><br><span>+        timeout = epow_timeout[EPOW_POWER_UPS];</span><br><span>+    }</span><br><span>+</span><br><span>+    if (epow_status[OPAL_EPOW_POWER] & OPAL_EPOW_POWER_UPS_LOW) {</span><br><span>+        pr_info("EPOW due to system running on UPS power "</span><br><span>+                "with low battery\n</span><br><span>+        event = EPOW_POWER_UPS_LOW;</span><br><span>+        timeout = epow_timeout[EPOW_POWER_UPS_LOW];</span><br><span>+    }</span><br><span>+</span><br><span>+    if (epow_status[OPAL_EPOW_TEMP] & OPAL_EPOW_TEMP_HIGH_AMB) {</span><br><span>+        pr_info("EPOW due to high ambient temperature\n");</span><br><span>+        event = EPOW_TEMP_HIGH_AMB;</span><br><span>+        timeout = epow_timeout[EPOW_TEMP_HIGH_AMB];</span><br><span>+    }</span><br><span>+</span><br><span>+    if (epow_status[OPAL_EPOW_TEMP] & OPAL_EPOW_TEMP_CRIT_AMB) {</span><br><span>+        pr_info("EPOW due to critical ambient temperature\n");</span><br><span>+        event = EPOW_TEMP_CRIT_AMB;</span><br><span>+        timeout = epow_timeout[EPOW_TEMP_CRIT_AMB];</span><br><span>+    }</span><br><span>+</span><br><span>+    if (epow_status[OPAL_EPOW_TEMP] & OPAL_EPOW_TEMP_HIGH_INT) {</span><br><span>+        pr_info("EPOW due to high internal temperature\n");</span><br><span>+        event = EPOW_TEMP_HIGH_INT;</span><br><span>+        timeout = epow_timeout[EPOW_TEMP_HIGH_INT];</span><br><span>+    }</span><br><span>+</span><br><span>+    if (epow_status[OPAL_EPOW_TEMP] & OPAL_EPOW_TEMP_CRIT_INT) {</span><br><span>+        pr_info("EPOW due to critical internal temperature\n");</span><br><span>+        event = EPOW_TEMP_CRIT_INT;</span><br><span>+        timeout = epow_timeout[EPOW_TEMP_CRIT_INT];</span><br><span>+    }</span><br><span>+</span><br><span>+    if (event == -1) {</span><br><span>+        pr_err("Unknown EPOW event\n");</span><br><span>+        return;</span><br><span>+    }</span><br><span>+</span><br><span>+    /* Start EPOW poweroff timer */</span><br><span>+    start_epow_timer(event, timeout);</span><br><span>+}</span><br><span>+</span><br><span>+/* Check for any existing EPOW, DPO events and process them, if existing */</span><br><span>+static void process_existing_poweroff_events(void)</span><br><span>+{</span><br><span>+    int rc;</span><br><span>+    int32_t dpo_timeout;</span><br><span>+</span><br><span>+    /* Check for any existing DPO event */</span><br><span>+    rc = get_dpo_status(&dpo_timeout);</span><br><span>+    if (rc == DPO_DETECTED) {</span><br><span>+        pr_info("Existing DPO event detected\n");</span><br><span>+        process_dpo();</span><br><span>+        return;</span></div></blockquote><blockquote type="cite"><div><span>+     } else</span><br><span>+        pr_info("No existing DPO event detected\n");</span><br><span>+</span><br><span>+    /* Check for any existing EPOW event */</span><br><span>+    rc = get_epow_status();</span><br><span>+    if (rc == EPOW_DETECTED) {</span><br><span>+        pr_info("Existing EPOW event detected.\n");</span><br><span>+        process_epow();</span><br><span>+    } else</span><br><span>+        pr_info("No existing EPOW event detected\n");</span><br><span>+</span><br><span>+}</span><br><span>+</span><br><span>+/* Platform EPOW message received */</span><br><span>+static int opal_epow_event(struct notifier_block *nb,</span><br><span>+            unsigned long msg_type, void *msg)</span><br><span>+{</span><br><span>+    pr_info("EPOW event received\n");</span><br><span>+</span><br><span>+    /* Get EPOW event details */</span><br><span>+    get_epow_status();</span><br><span>+</span><br><span>+    /* Process EPOW event information */</span><br><span>+    process_epow();</span><br><span>+</span><br><span>+    return 0;</span><br><span>+}</span><br><span>+</span><br><span>+</span><br><span>+/* Platform DPO message received */</span><br><span>+static int opal_dpo_event(struct notifier_block *nb,</span><br><span>+                unsigned long msg_type, void *msg)</span><br><span>+{</span><br><span>+    pr_info("DPO event received.\n");</span><br><span>+    process_dpo();</span><br><span>+</span><br><span>+    return 0;</span><br><span>+}</span><br><span>+</span><br><span>+</span><br><span>+/* OPAL EPOW event notifier block */</span><br><span>+static struct notifier_block opal_epow_nb = {</span><br><span>+    .notifier_call  = opal_epow_event,</span><br><span>+    .next           = NULL,</span><br><span>+    .priority       = 0,</span><br><span>+};</span><br><span>+</span><br><span>+/* OPAL DPO event notifier block */</span><br><span>+static struct notifier_block opal_dpo_nb = {</span><br><span>+    .notifier_call  = opal_dpo_event,</span><br><span>+    .next           = NULL,</span><br><span>+    .priority       = 0,</span><br><span>+};</span><br><span>+</span><br><span>+/* Poweroff events init */</span><br><span>+static int opal_poweroff_events_init(void)</span><br><span>+{</span><br><span>+    int ret;</span><br><span>+</span><br><span>+    /* Initialize poweroff timer */</span><br><span>+    init_timer(&epow_timer);</span><br><span>+    epow_timer.function = epow_poweroff;</span><br><span>+</span><br><span>+    /* Get EPOW event timeout values */</span><br><span>+    get_epow_timeouts();</span><br><span>+</span><br><span>+    /* Check for any existing EPOW or DPO events. */</span><br><span>+    process_existing_poweroff_events();</span><br><span>+</span><br><span>+    /* Register EPOW event notifier */</span><br><span>+    ret = opal_message_notifier_register(OPAL_MSG_EPOW, &opal_epow_nb);</span><br><span>+    if (ret) {</span><br><span>+        pr_err("EPOW event notifier registration failed\n");</span><br><span>+        return ret;</span><br><span>+    }</span><br></div></blockquote>Timing issue. You may miss some events that occur between process existing power off event and registering message notifies. Instead first register your notifier  and then process any existing  events.<br><blockquote type="cite"><div><span>+</span><br><span>+    /* Register DPO event notifier */</span><br><span>+    ret = opal_message_notifier_register(OPAL_MSG_DPO, &opal_dpo_nb);</span><br><span>+    if (ret) {</span><br><span>+        pr_err("DPO event notifier registration failed\n");</span><br><span>+        opal_notifier_unregister(&opal_epow_nb);</span><br><span>+        return ret;</span><br><span>+    }</span><br><span>+</span><br><span>+</span><br><span>+    pr_info("OPAL poweroff events support initialized\n");</span><br><span>+</span><br><span>+    return 0;</span><br><span>+}</span><br><span>+</span><br><span>+machine_subsys_initcall(powernv, opal_poweroff_events_init);</span><br><span>diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S</span><br><span>index a7ade94..5d3c8e3 100644</span><br><span>--- a/arch/powerpc/platforms/powernv/opal-wrappers.S</span><br><span>+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S</span><br><span>@@ -249,6 +249,7 @@ OPAL_CALL(opal_pci_reinit,            OPAL_PCI_REINIT);</span><br><span> OPAL_CALL(opal_pci_mask_pe_error,        OPAL_PCI_MASK_PE_ERROR);</span><br><span> OPAL_CALL(opal_set_slot_led_status,        OPAL_SET_SLOT_LED_STATUS);</span><br><span> OPAL_CALL(opal_get_epow_status,            OPAL_GET_EPOW_STATUS);</span><br><span>+OPAL_CALL(opal_get_dpo_status,            OPAL_GET_DPO_STATUS);</span><br><span> OPAL_CALL(opal_set_system_attention_led,    OPAL_SET_SYSTEM_ATTENTION_LED);</span><br><span> OPAL_CALL(opal_pci_next_error,            OPAL_PCI_NEXT_ERROR);</span><br><span> OPAL_CALL(opal_pci_poll,            OPAL_PCI_POLL);</span><br><span>-- </span><br><span>1.9.3</span><br><span></span><br><span>_______________________________________________</span><br><span>Linuxppc-dev mailing list</span><br><span><a href="mailto:Linuxppc-dev@lists.ozlabs.org">Linuxppc-dev@lists.ozlabs.org</a></span><br><span><a href="https://lists.ozlabs.org/listinfo/linuxppc-dev">https://lists.ozlabs.org/listinfo/linuxppc-dev</a></span></div></blockquote></div></body></html>