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

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

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

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

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

kernel.org | git.kernel.org | LWN.net | Project Home | 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.

sflogo.php