2 * PowerNV OPAL power control for graceful shutdown handling
4 * Copyright 2015 IBM Corp.
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
12 #define pr_fmt(fmt) "opal-power: " fmt
14 #include <linux/kernel.h>
15 #include <linux/reboot.h>
16 #include <linux/notifier.h>
20 #include <asm/machdep.h>
23 #define SOFT_REBOOT 0x01
25 /* Detect EPOW event */
26 static bool detect_epow(void)
31 __be16 opal_epow_status
[OPAL_SYSEPOW_MAX
] = {0};
34 * Check for EPOW event. Kernel sends supported EPOW classes info
35 * to OPAL. OPAL returns EPOW info along with classes present.
37 epow_classes
= cpu_to_be16(OPAL_SYSEPOW_MAX
);
38 rc
= opal_get_epow_status(opal_epow_status
, &epow_classes
);
39 if (rc
!= OPAL_SUCCESS
) {
40 pr_err("Failed to get EPOW event information\n");
44 /* Look for EPOW events present */
45 for (i
= 0; i
< be16_to_cpu(epow_classes
); i
++) {
46 epow
= be16_to_cpu(opal_epow_status
[i
]);
48 /* Filter events which do not need shutdown. */
49 if (i
== OPAL_SYSEPOW_POWER
)
50 epow
&= ~(OPAL_SYSPOWER_CHNG
| OPAL_SYSPOWER_FAIL
|
59 /* Check for existing EPOW, DPO events */
60 static bool poweroff_pending(void)
63 __be64 opal_dpo_timeout
;
65 /* Check for DPO event */
66 rc
= opal_get_dpo_status(&opal_dpo_timeout
);
67 if (rc
== OPAL_SUCCESS
) {
68 pr_info("Existing DPO event detected.\n");
72 /* Check for EPOW event */
74 pr_info("Existing EPOW event detected.\n");
81 /* OPAL power-control events notifier */
82 static int opal_power_control_event(struct notifier_block
*nb
,
83 unsigned long msg_type
, void *msg
)
90 pr_info("EPOW msg received. Powering off system\n");
91 orderly_poweroff(true);
95 pr_info("DPO msg received. Powering off system\n");
96 orderly_poweroff(true);
98 case OPAL_MSG_SHUTDOWN
:
99 type
= be64_to_cpu(((struct opal_msg
*)msg
)->params
[0]);
102 pr_info("Reboot requested\n");
106 pr_info("Poweroff requested\n");
107 orderly_poweroff(true);
110 pr_err("Unknown power-control type %llu\n", type
);
114 pr_err("Unknown OPAL message type %lu\n", msg_type
);
120 /* OPAL EPOW event notifier block */
121 static struct notifier_block opal_epow_nb
= {
122 .notifier_call
= opal_power_control_event
,
127 /* OPAL DPO event notifier block */
128 static struct notifier_block opal_dpo_nb
= {
129 .notifier_call
= opal_power_control_event
,
134 /* OPAL power-control event notifier block */
135 static struct notifier_block opal_power_control_nb
= {
136 .notifier_call
= opal_power_control_event
,
141 static int __init
opal_power_control_init(void)
143 int ret
, supported
= 0;
144 struct device_node
*np
;
146 /* Register OPAL power-control events notifier */
147 ret
= opal_message_notifier_register(OPAL_MSG_SHUTDOWN
,
148 &opal_power_control_nb
);
150 pr_err("Failed to register SHUTDOWN notifier, ret = %d\n", ret
);
152 /* Determine OPAL EPOW, DPO support */
153 np
= of_find_node_by_path("/ibm,opal/epow");
155 supported
= of_device_is_compatible(np
, "ibm,opal-v3-epow");
161 pr_info("OPAL EPOW, DPO support detected.\n");
163 /* Register EPOW event notifier */
164 ret
= opal_message_notifier_register(OPAL_MSG_EPOW
, &opal_epow_nb
);
166 pr_err("Failed to register EPOW notifier, ret = %d\n", ret
);
168 /* Register DPO event notifier */
169 ret
= opal_message_notifier_register(OPAL_MSG_DPO
, &opal_dpo_nb
);
171 pr_err("Failed to register DPO notifier, ret = %d\n", ret
);
173 /* Check for any pending EPOW or DPO events. */
174 if (poweroff_pending())
175 orderly_poweroff(true);
179 machine_subsys_initcall(powernv
, opal_power_control_init
);