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

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

Version: ~ [ linux-5.2-rc1 ] ~ [ linux-5.1.2 ] ~ [ linux-5.0.16 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.43 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.119 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.176 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.179 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.139 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.67 ] ~ [ 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   * Copyright (C) 2010 Brian King IBM Corporation
  3   *
  4   * This program is free software; you can redistribute it and/or modify
  5   * it under the terms of the GNU General Public License as published by
  6   * the Free Software Foundation; either version 2 of the License, or
  7   * (at your option) any later version.
  8   *
  9   * This program is distributed in the hope that it will be useful,
 10   * but WITHOUT ANY WARRANTY; without even the implied warranty of
 11   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 12   * GNU General Public License for more details.
 13   *
 14   * You should have received a copy of the GNU General Public License
 15   * along with this program; if not, write to the Free Software
 16   * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 17   */
 18 
 19 #include <linux/delay.h>
 20 #include <linux/suspend.h>
 21 #include <asm/firmware.h>
 22 #include <asm/hvcall.h>
 23 #include <asm/machdep.h>
 24 #include <asm/mmu.h>
 25 #include <asm/rtas.h>
 26 
 27 static u64 stream_id;
 28 static struct sys_device suspend_sysdev;
 29 static DECLARE_COMPLETION(suspend_work);
 30 static struct rtas_suspend_me_data suspend_data;
 31 static atomic_t suspending;
 32 
 33 /**
 34  * pseries_suspend_begin - First phase of hibernation
 35  *
 36  * Check to ensure we are in a valid state to hibernate
 37  *
 38  * Return value:
 39  *      0 on success / other on failure
 40  **/
 41 static int pseries_suspend_begin(suspend_state_t state)
 42 {
 43         long vasi_state, rc;
 44         unsigned long retbuf[PLPAR_HCALL_BUFSIZE];
 45 
 46         /* Make sure the state is valid */
 47         rc = plpar_hcall(H_VASI_STATE, retbuf, stream_id);
 48 
 49         vasi_state = retbuf[0];
 50 
 51         if (rc) {
 52                 pr_err("pseries_suspend_begin: vasi_state returned %ld\n",rc);
 53                 return rc;
 54         } else if (vasi_state == H_VASI_ENABLED) {
 55                 return -EAGAIN;
 56         } else if (vasi_state != H_VASI_SUSPENDING) {
 57                 pr_err("pseries_suspend_begin: vasi_state returned state %ld\n",
 58                        vasi_state);
 59                 return -EIO;
 60         }
 61 
 62         return 0;
 63 }
 64 
 65 /**
 66  * pseries_suspend_cpu - Suspend a single CPU
 67  *
 68  * Makes the H_JOIN call to suspend the CPU
 69  *
 70  **/
 71 static int pseries_suspend_cpu(void)
 72 {
 73         if (atomic_read(&suspending))
 74                 return rtas_suspend_cpu(&suspend_data);
 75         return 0;
 76 }
 77 
 78 /**
 79  * pseries_suspend_enter - Final phase of hibernation
 80  *
 81  * Return value:
 82  *      0 on success / other on failure
 83  **/
 84 static int pseries_suspend_enter(suspend_state_t state)
 85 {
 86         int rc = rtas_suspend_last_cpu(&suspend_data);
 87 
 88         atomic_set(&suspending, 0);
 89         atomic_set(&suspend_data.done, 1);
 90         return rc;
 91 }
 92 
 93 /**
 94  * pseries_prepare_late - Prepare to suspend all other CPUs
 95  *
 96  * Return value:
 97  *      0 on success / other on failure
 98  **/
 99 static int pseries_prepare_late(void)
100 {
101         atomic_set(&suspending, 1);
102         atomic_set(&suspend_data.working, 0);
103         atomic_set(&suspend_data.done, 0);
104         atomic_set(&suspend_data.error, 0);
105         suspend_data.complete = &suspend_work;
106         INIT_COMPLETION(suspend_work);
107         return 0;
108 }
109 
110 /**
111  * store_hibernate - Initiate partition hibernation
112  * @classdev:   sysdev class struct
113  * @attr:               class device attribute struct
114  * @buf:                buffer
115  * @count:              buffer size
116  *
117  * Write the stream ID received from the HMC to this file
118  * to trigger hibernating the partition
119  *
120  * Return value:
121  *      number of bytes printed to buffer / other on failure
122  **/
123 static ssize_t store_hibernate(struct sysdev_class *classdev,
124                                struct sysdev_class_attribute *attr,
125                                const char *buf, size_t count)
126 {
127         int rc;
128 
129         if (!capable(CAP_SYS_ADMIN))
130                 return -EPERM;
131 
132         stream_id = simple_strtoul(buf, NULL, 16);
133 
134         do {
135                 rc = pseries_suspend_begin(PM_SUSPEND_MEM);
136                 if (rc == -EAGAIN)
137                         ssleep(1);
138         } while (rc == -EAGAIN);
139 
140         if (!rc)
141                 rc = pm_suspend(PM_SUSPEND_MEM);
142 
143         stream_id = 0;
144 
145         if (!rc)
146                 rc = count;
147         return rc;
148 }
149 
150 static SYSDEV_CLASS_ATTR(hibernate, S_IWUSR, NULL, store_hibernate);
151 
152 static struct sysdev_class suspend_sysdev_class = {
153         .name = "power",
154 };
155 
156 static const struct platform_suspend_ops pseries_suspend_ops = {
157         .valid          = suspend_valid_only_mem,
158         .begin          = pseries_suspend_begin,
159         .prepare_late   = pseries_prepare_late,
160         .enter          = pseries_suspend_enter,
161 };
162 
163 /**
164  * pseries_suspend_sysfs_register - Register with sysfs
165  *
166  * Return value:
167  *      0 on success / other on failure
168  **/
169 static int pseries_suspend_sysfs_register(struct sys_device *sysdev)
170 {
171         int rc;
172 
173         if ((rc = sysdev_class_register(&suspend_sysdev_class)))
174                 return rc;
175 
176         sysdev->id = 0;
177         sysdev->cls = &suspend_sysdev_class;
178 
179         if ((rc = sysdev_class_create_file(&suspend_sysdev_class, &attr_hibernate)))
180                 goto class_unregister;
181 
182         return 0;
183 
184 class_unregister:
185         sysdev_class_unregister(&suspend_sysdev_class);
186         return rc;
187 }
188 
189 /**
190  * pseries_suspend_init - initcall for pSeries suspend
191  *
192  * Return value:
193  *      0 on success / other on failure
194  **/
195 static int __init pseries_suspend_init(void)
196 {
197         int rc;
198 
199         if (!machine_is(pseries) || !firmware_has_feature(FW_FEATURE_LPAR))
200                 return 0;
201 
202         suspend_data.token = rtas_token("ibm,suspend-me");
203         if (suspend_data.token == RTAS_UNKNOWN_SERVICE)
204                 return 0;
205 
206         if ((rc = pseries_suspend_sysfs_register(&suspend_sysdev)))
207                 return rc;
208 
209         ppc_md.suspend_disable_cpu = pseries_suspend_cpu;
210         suspend_set_ops(&pseries_suspend_ops);
211         return 0;
212 }
213 
214 __initcall(pseries_suspend_init);
215 

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