0001
0002
0003
0004
0005
0006
0007
0008 #define pr_fmt(fmt) "opal-power: " fmt
0009
0010 #include <linux/kernel.h>
0011 #include <linux/reboot.h>
0012 #include <linux/notifier.h>
0013 #include <linux/of.h>
0014
0015 #include <asm/opal.h>
0016 #include <asm/machdep.h>
0017
0018 #define SOFT_OFF 0x00
0019 #define SOFT_REBOOT 0x01
0020
0021
0022 static bool detect_epow(void)
0023 {
0024 u16 epow;
0025 int i, rc;
0026 __be16 epow_classes;
0027 __be16 opal_epow_status[OPAL_SYSEPOW_MAX] = {0};
0028
0029
0030
0031
0032
0033 epow_classes = cpu_to_be16(OPAL_SYSEPOW_MAX);
0034 rc = opal_get_epow_status(opal_epow_status, &epow_classes);
0035 if (rc != OPAL_SUCCESS) {
0036 pr_err("Failed to get EPOW event information\n");
0037 return false;
0038 }
0039
0040
0041 for (i = 0; i < be16_to_cpu(epow_classes); i++) {
0042 epow = be16_to_cpu(opal_epow_status[i]);
0043
0044
0045 if (i == OPAL_SYSEPOW_POWER)
0046 epow &= ~(OPAL_SYSPOWER_CHNG | OPAL_SYSPOWER_FAIL |
0047 OPAL_SYSPOWER_INCL);
0048 if (epow)
0049 return true;
0050 }
0051
0052 return false;
0053 }
0054
0055
0056 static bool __init poweroff_pending(void)
0057 {
0058 int rc;
0059 __be64 opal_dpo_timeout;
0060
0061
0062 rc = opal_get_dpo_status(&opal_dpo_timeout);
0063 if (rc == OPAL_SUCCESS) {
0064 pr_info("Existing DPO event detected.\n");
0065 return true;
0066 }
0067
0068
0069 if (detect_epow()) {
0070 pr_info("Existing EPOW event detected.\n");
0071 return true;
0072 }
0073
0074 return false;
0075 }
0076
0077
0078 static int opal_power_control_event(struct notifier_block *nb,
0079 unsigned long msg_type, void *msg)
0080 {
0081 uint64_t type;
0082
0083 switch (msg_type) {
0084 case OPAL_MSG_EPOW:
0085 if (detect_epow()) {
0086 pr_info("EPOW msg received. Powering off system\n");
0087 orderly_poweroff(true);
0088 }
0089 break;
0090 case OPAL_MSG_DPO:
0091 pr_info("DPO msg received. Powering off system\n");
0092 orderly_poweroff(true);
0093 break;
0094 case OPAL_MSG_SHUTDOWN:
0095 type = be64_to_cpu(((struct opal_msg *)msg)->params[0]);
0096 switch (type) {
0097 case SOFT_REBOOT:
0098 pr_info("Reboot requested\n");
0099 orderly_reboot();
0100 break;
0101 case SOFT_OFF:
0102 pr_info("Poweroff requested\n");
0103 orderly_poweroff(true);
0104 break;
0105 default:
0106 pr_err("Unknown power-control type %llu\n", type);
0107 }
0108 break;
0109 default:
0110 pr_err("Unknown OPAL message type %lu\n", msg_type);
0111 }
0112
0113 return 0;
0114 }
0115
0116
0117 static struct notifier_block opal_epow_nb = {
0118 .notifier_call = opal_power_control_event,
0119 .next = NULL,
0120 .priority = 0,
0121 };
0122
0123
0124 static struct notifier_block opal_dpo_nb = {
0125 .notifier_call = opal_power_control_event,
0126 .next = NULL,
0127 .priority = 0,
0128 };
0129
0130
0131 static struct notifier_block opal_power_control_nb = {
0132 .notifier_call = opal_power_control_event,
0133 .next = NULL,
0134 .priority = 0,
0135 };
0136
0137 int __init opal_power_control_init(void)
0138 {
0139 int ret, supported = 0;
0140 struct device_node *np;
0141
0142
0143 ret = opal_message_notifier_register(OPAL_MSG_SHUTDOWN,
0144 &opal_power_control_nb);
0145 if (ret)
0146 pr_err("Failed to register SHUTDOWN notifier, ret = %d\n", ret);
0147
0148
0149 np = of_find_node_by_path("/ibm,opal/epow");
0150 if (np) {
0151 supported = of_device_is_compatible(np, "ibm,opal-v3-epow");
0152 of_node_put(np);
0153 }
0154
0155 if (!supported)
0156 return 0;
0157 pr_info("OPAL EPOW, DPO support detected.\n");
0158
0159
0160 ret = opal_message_notifier_register(OPAL_MSG_EPOW, &opal_epow_nb);
0161 if (ret)
0162 pr_err("Failed to register EPOW notifier, ret = %d\n", ret);
0163
0164
0165 ret = opal_message_notifier_register(OPAL_MSG_DPO, &opal_dpo_nb);
0166 if (ret)
0167 pr_err("Failed to register DPO notifier, ret = %d\n", ret);
0168
0169
0170 if (poweroff_pending())
0171 orderly_poweroff(true);
0172
0173 return 0;
0174 }