~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/powernv/opal-power.c

Version: ~ [ linux-5.2 ] ~ [ linux-5.1.16 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.57 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.132 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.184 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.184 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.69 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * PowerNV OPAL power control for graceful shutdown handling
  3  *
  4  * Copyright 2015 IBM Corp.
  5  *
  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.
 10  */
 11 
 12 #define pr_fmt(fmt)     "opal-power: "  fmt
 13 
 14 #include <linux/kernel.h>
 15 #include <linux/reboot.h>
 16 #include <linux/notifier.h>
 17 #include <linux/of.h>
 18 
 19 #include <asm/opal.h>
 20 #include <asm/machdep.h>
 21 
 22 #define SOFT_OFF 0x00
 23 #define SOFT_REBOOT 0x01
 24 
 25 /* Detect EPOW event */
 26 static bool detect_epow(void)
 27 {
 28         u16 epow;
 29         int i, rc;
 30         __be16 epow_classes;
 31         __be16 opal_epow_status[OPAL_SYSEPOW_MAX] = {0};
 32 
 33         /*
 34         * Check for EPOW event. Kernel sends supported EPOW classes info
 35         * to OPAL. OPAL returns EPOW info along with classes present.
 36         */
 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");
 41                 return false;
 42         }
 43 
 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]);
 47 
 48                 /* Filter events which do not need shutdown. */
 49                 if (i == OPAL_SYSEPOW_POWER)
 50                         epow &= ~(OPAL_SYSPOWER_CHNG | OPAL_SYSPOWER_FAIL |
 51                                         OPAL_SYSPOWER_INCL);
 52                 if (epow)
 53                         return true;
 54         }
 55 
 56         return false;
 57 }
 58 
 59 /* Check for existing EPOW, DPO events */
 60 static bool poweroff_pending(void)
 61 {
 62         int rc;
 63         __be64 opal_dpo_timeout;
 64 
 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");
 69                 return true;
 70         }
 71 
 72         /* Check for EPOW event */
 73         if (detect_epow()) {
 74                 pr_info("Existing EPOW event detected.\n");
 75                 return true;
 76         }
 77 
 78         return false;
 79 }
 80 
 81 /* OPAL power-control events notifier */
 82 static int opal_power_control_event(struct notifier_block *nb,
 83                                         unsigned long msg_type, void *msg)
 84 {
 85         uint64_t type;
 86 
 87         switch (msg_type) {
 88         case OPAL_MSG_EPOW:
 89                 if (detect_epow()) {
 90                         pr_info("EPOW msg received. Powering off system\n");
 91                         orderly_poweroff(true);
 92                 }
 93                 break;
 94         case OPAL_MSG_DPO:
 95                 pr_info("DPO msg received. Powering off system\n");
 96                 orderly_poweroff(true);
 97                 break;
 98         case OPAL_MSG_SHUTDOWN:
 99                 type = be64_to_cpu(((struct opal_msg *)msg)->params[0]);
100                 switch (type) {
101                 case SOFT_REBOOT:
102                         pr_info("Reboot requested\n");
103                         orderly_reboot();
104                         break;
105                 case SOFT_OFF:
106                         pr_info("Poweroff requested\n");
107                         orderly_poweroff(true);
108                         break;
109                 default:
110                         pr_err("Unknown power-control type %llu\n", type);
111                 }
112                 break;
113         default:
114                 pr_err("Unknown OPAL message type %lu\n", msg_type);
115         }
116 
117         return 0;
118 }
119 
120 /* OPAL EPOW event notifier block */
121 static struct notifier_block opal_epow_nb = {
122         .notifier_call  = opal_power_control_event,
123         .next           = NULL,
124         .priority       = 0,
125 };
126 
127 /* OPAL DPO event notifier block */
128 static struct notifier_block opal_dpo_nb = {
129         .notifier_call  = opal_power_control_event,
130         .next           = NULL,
131         .priority       = 0,
132 };
133 
134 /* OPAL power-control event notifier block */
135 static struct notifier_block opal_power_control_nb = {
136         .notifier_call  = opal_power_control_event,
137         .next           = NULL,
138         .priority       = 0,
139 };
140 
141 static int __init opal_power_control_init(void)
142 {
143         int ret, supported = 0;
144         struct device_node *np;
145 
146         /* Register OPAL power-control events notifier */
147         ret = opal_message_notifier_register(OPAL_MSG_SHUTDOWN,
148                                                 &opal_power_control_nb);
149         if (ret)
150                 pr_err("Failed to register SHUTDOWN notifier, ret = %d\n", ret);
151 
152         /* Determine OPAL EPOW, DPO support */
153         np = of_find_node_by_path("/ibm,opal/epow");
154         if (np) {
155                 supported = of_device_is_compatible(np, "ibm,opal-v3-epow");
156                 of_node_put(np);
157         }
158 
159         if (!supported)
160                 return 0;
161         pr_info("OPAL EPOW, DPO support detected.\n");
162 
163         /* Register EPOW event notifier */
164         ret = opal_message_notifier_register(OPAL_MSG_EPOW, &opal_epow_nb);
165         if (ret)
166                 pr_err("Failed to register EPOW notifier, ret = %d\n", ret);
167 
168         /* Register DPO event notifier */
169         ret = opal_message_notifier_register(OPAL_MSG_DPO, &opal_dpo_nb);
170         if (ret)
171                 pr_err("Failed to register DPO notifier, ret = %d\n", ret);
172 
173         /* Check for any pending EPOW or DPO events. */
174         if (poweroff_pending())
175                 orderly_poweroff(true);
176 
177         return 0;
178 }
179 machine_subsys_initcall(powernv, opal_power_control_init);
180 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp