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

TOMOYO Linux Cross Reference
Linux/arch/powerpc/platforms/pseries/suspend.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ 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   * Copyright (C) 2010 Brian King IBM Corporation
  4   */
  5 
  6 #include <linux/cpu.h>
  7 #include <linux/delay.h>
  8 #include <linux/suspend.h>
  9 #include <linux/stat.h>
 10 #include <asm/firmware.h>
 11 #include <asm/hvcall.h>
 12 #include <asm/machdep.h>
 13 #include <asm/mmu.h>
 14 #include <asm/rtas.h>
 15 #include <asm/topology.h>
 16 #include "pseries.h"
 17 
 18 static struct device suspend_dev;
 19 
 20 /**
 21  * pseries_suspend_begin - First phase of hibernation
 22  *
 23  * Check to ensure we are in a valid state to hibernate
 24  *
 25  * Return value:
 26  *      0 on success / other on failure
 27  **/
 28 static int pseries_suspend_begin(u64 stream_id)
 29 {
 30         long vasi_state, rc;
 31         unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
 32 
 33         /* Make sure the state is valid */
 34         rc = plpar_hcall(H_VASI_STATE, retbuf, stream_id);
 35 
 36         vasi_state = retbuf[0];
 37 
 38         if (rc) {
 39                 pr_err("pseries_suspend_begin: vasi_state returned %ld\n",rc);
 40                 return rc;
 41         } else if (vasi_state == H_VASI_ENABLED) {
 42                 return -EAGAIN;
 43         } else if (vasi_state != H_VASI_SUSPENDING) {
 44                 pr_err("pseries_suspend_begin: vasi_state returned state %ld\n",
 45                        vasi_state);
 46                 return -EIO;
 47         }
 48         return 0;
 49 }
 50 
 51 /**
 52  * pseries_suspend_enter - Final phase of hibernation
 53  *
 54  * Return value:
 55  *      0 on success / other on failure
 56  **/
 57 static int pseries_suspend_enter(suspend_state_t state)
 58 {
 59         return rtas_ibm_suspend_me(NULL);
 60 }
 61 
 62 /**
 63  * store_hibernate - Initiate partition hibernation
 64  * @dev:                subsys root device
 65  * @attr:               device attribute struct
 66  * @buf:                buffer
 67  * @count:              buffer size
 68  *
 69  * Write the stream ID received from the HMC to this file
 70  * to trigger hibernating the partition
 71  *
 72  * Return value:
 73  *      number of bytes printed to buffer / other on failure
 74  **/
 75 static ssize_t store_hibernate(struct device *dev,
 76                                struct device_attribute *attr,
 77                                const char *buf, size_t count)
 78 {
 79         u64 stream_id;
 80         int rc;
 81 
 82         if (!capable(CAP_SYS_ADMIN))
 83                 return -EPERM;
 84 
 85         stream_id = simple_strtoul(buf, NULL, 16);
 86 
 87         do {
 88                 rc = pseries_suspend_begin(stream_id);
 89                 if (rc == -EAGAIN)
 90                         ssleep(1);
 91         } while (rc == -EAGAIN);
 92 
 93         if (!rc)
 94                 rc = pm_suspend(PM_SUSPEND_MEM);
 95 
 96         if (!rc) {
 97                 rc = count;
 98                 post_mobility_fixup();
 99         }
100 
101 
102         return rc;
103 }
104 
105 #define USER_DT_UPDATE  0
106 #define KERN_DT_UPDATE  1
107 
108 /**
109  * show_hibernate - Report device tree update responsibilty
110  * @dev:                subsys root device
111  * @attr:               device attribute struct
112  * @buf:                buffer
113  *
114  * Report whether a device tree update is performed by the kernel after a
115  * resume, or if drmgr must coordinate the update from user space.
116  *
117  * Return value:
118  *      0 if drmgr is to initiate update, and 1 otherwise
119  **/
120 static ssize_t show_hibernate(struct device *dev,
121                               struct device_attribute *attr,
122                               char *buf)
123 {
124         return sprintf(buf, "%d\n", KERN_DT_UPDATE);
125 }
126 
127 static DEVICE_ATTR(hibernate, 0644, show_hibernate, store_hibernate);
128 
129 static struct bus_type suspend_subsys = {
130         .name = "power",
131         .dev_name = "power",
132 };
133 
134 static const struct platform_suspend_ops pseries_suspend_ops = {
135         .valid          = suspend_valid_only_mem,
136         .enter          = pseries_suspend_enter,
137 };
138 
139 /**
140  * pseries_suspend_sysfs_register - Register with sysfs
141  *
142  * Return value:
143  *      0 on success / other on failure
144  **/
145 static int pseries_suspend_sysfs_register(struct device *dev)
146 {
147         struct device *dev_root;
148         int rc;
149 
150         if ((rc = subsys_system_register(&suspend_subsys, NULL)))
151                 return rc;
152 
153         dev->id = 0;
154         dev->bus = &suspend_subsys;
155 
156         dev_root = bus_get_dev_root(&suspend_subsys);
157         if (dev_root) {
158                 rc = device_create_file(dev_root, &dev_attr_hibernate);
159                 put_device(dev_root);
160                 if (rc)
161                         goto subsys_unregister;
162         }
163 
164         return 0;
165 
166 subsys_unregister:
167         bus_unregister(&suspend_subsys);
168         return rc;
169 }
170 
171 /**
172  * pseries_suspend_init - initcall for pSeries suspend
173  *
174  * Return value:
175  *      0 on success / other on failure
176  **/
177 static int __init pseries_suspend_init(void)
178 {
179         int rc;
180 
181         if (!firmware_has_feature(FW_FEATURE_LPAR))
182                 return 0;
183 
184         if ((rc = pseries_suspend_sysfs_register(&suspend_dev)))
185                 return rc;
186 
187         suspend_set_ops(&pseries_suspend_ops);
188         return 0;
189 }
190 machine_device_initcall(pseries, pseries_suspend_init);
191 

~ [ 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