xref: /openbmc/linux/kernel/power/user.c (revision de2fe5e0)
1 /*
2  * linux/kernel/power/user.c
3  *
4  * This file provides the user space interface for software suspend/resume.
5  *
6  * Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
7  *
8  * This file is released under the GPLv2.
9  *
10  */
11 
12 #include <linux/suspend.h>
13 #include <linux/syscalls.h>
14 #include <linux/string.h>
15 #include <linux/device.h>
16 #include <linux/miscdevice.h>
17 #include <linux/mm.h>
18 #include <linux/swap.h>
19 #include <linux/swapops.h>
20 #include <linux/pm.h>
21 #include <linux/fs.h>
22 
23 #include <asm/uaccess.h>
24 
25 #include "power.h"
26 
27 #define SNAPSHOT_MINOR	231
28 
29 static struct snapshot_data {
30 	struct snapshot_handle handle;
31 	int swap;
32 	struct bitmap_page *bitmap;
33 	int mode;
34 	char frozen;
35 	char ready;
36 } snapshot_state;
37 
38 static atomic_t device_available = ATOMIC_INIT(1);
39 
40 static int snapshot_open(struct inode *inode, struct file *filp)
41 {
42 	struct snapshot_data *data;
43 
44 	if (!atomic_add_unless(&device_available, -1, 0))
45 		return -EBUSY;
46 
47 	if ((filp->f_flags & O_ACCMODE) == O_RDWR)
48 		return -ENOSYS;
49 
50 	nonseekable_open(inode, filp);
51 	data = &snapshot_state;
52 	filp->private_data = data;
53 	memset(&data->handle, 0, sizeof(struct snapshot_handle));
54 	if ((filp->f_flags & O_ACCMODE) == O_RDONLY) {
55 		data->swap = swsusp_resume_device ? swap_type_of(swsusp_resume_device) : -1;
56 		data->mode = O_RDONLY;
57 	} else {
58 		data->swap = -1;
59 		data->mode = O_WRONLY;
60 	}
61 	data->bitmap = NULL;
62 	data->frozen = 0;
63 	data->ready = 0;
64 
65 	return 0;
66 }
67 
68 static int snapshot_release(struct inode *inode, struct file *filp)
69 {
70 	struct snapshot_data *data;
71 
72 	swsusp_free();
73 	data = filp->private_data;
74 	free_all_swap_pages(data->swap, data->bitmap);
75 	free_bitmap(data->bitmap);
76 	if (data->frozen) {
77 		down(&pm_sem);
78 		thaw_processes();
79 		enable_nonboot_cpus();
80 		up(&pm_sem);
81 	}
82 	atomic_inc(&device_available);
83 	return 0;
84 }
85 
86 static ssize_t snapshot_read(struct file *filp, char __user *buf,
87                              size_t count, loff_t *offp)
88 {
89 	struct snapshot_data *data;
90 	ssize_t res;
91 
92 	data = filp->private_data;
93 	res = snapshot_read_next(&data->handle, count);
94 	if (res > 0) {
95 		if (copy_to_user(buf, data_of(data->handle), res))
96 			res = -EFAULT;
97 		else
98 			*offp = data->handle.offset;
99 	}
100 	return res;
101 }
102 
103 static ssize_t snapshot_write(struct file *filp, const char __user *buf,
104                               size_t count, loff_t *offp)
105 {
106 	struct snapshot_data *data;
107 	ssize_t res;
108 
109 	data = filp->private_data;
110 	res = snapshot_write_next(&data->handle, count);
111 	if (res > 0) {
112 		if (copy_from_user(data_of(data->handle), buf, res))
113 			res = -EFAULT;
114 		else
115 			*offp = data->handle.offset;
116 	}
117 	return res;
118 }
119 
120 static int snapshot_ioctl(struct inode *inode, struct file *filp,
121                           unsigned int cmd, unsigned long arg)
122 {
123 	int error = 0;
124 	struct snapshot_data *data;
125 	loff_t offset, avail;
126 
127 	if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
128 		return -ENOTTY;
129 	if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
130 		return -ENOTTY;
131 	if (!capable(CAP_SYS_ADMIN))
132 		return -EPERM;
133 
134 	data = filp->private_data;
135 
136 	switch (cmd) {
137 
138 	case SNAPSHOT_FREEZE:
139 		if (data->frozen)
140 			break;
141 		down(&pm_sem);
142 		disable_nonboot_cpus();
143 		if (freeze_processes()) {
144 			thaw_processes();
145 			enable_nonboot_cpus();
146 			error = -EBUSY;
147 		}
148 		up(&pm_sem);
149 		if (!error)
150 			data->frozen = 1;
151 		break;
152 
153 	case SNAPSHOT_UNFREEZE:
154 		if (!data->frozen)
155 			break;
156 		down(&pm_sem);
157 		thaw_processes();
158 		enable_nonboot_cpus();
159 		up(&pm_sem);
160 		data->frozen = 0;
161 		break;
162 
163 	case SNAPSHOT_ATOMIC_SNAPSHOT:
164 		if (data->mode != O_RDONLY || !data->frozen  || data->ready) {
165 			error = -EPERM;
166 			break;
167 		}
168 		down(&pm_sem);
169 		/* Free memory before shutting down devices. */
170 		error = swsusp_shrink_memory();
171 		if (!error) {
172 			error = device_suspend(PMSG_FREEZE);
173 			if (!error) {
174 				in_suspend = 1;
175 				error = swsusp_suspend();
176 				device_resume();
177 			}
178 		}
179 		up(&pm_sem);
180 		if (!error)
181 			error = put_user(in_suspend, (unsigned int __user *)arg);
182 		if (!error)
183 			data->ready = 1;
184 		break;
185 
186 	case SNAPSHOT_ATOMIC_RESTORE:
187 		if (data->mode != O_WRONLY || !data->frozen ||
188 		    !snapshot_image_loaded(&data->handle)) {
189 			error = -EPERM;
190 			break;
191 		}
192 		down(&pm_sem);
193 		pm_prepare_console();
194 		error = device_suspend(PMSG_FREEZE);
195 		if (!error) {
196 			error = swsusp_resume();
197 			device_resume();
198 		}
199 		pm_restore_console();
200 		up(&pm_sem);
201 		break;
202 
203 	case SNAPSHOT_FREE:
204 		swsusp_free();
205 		memset(&data->handle, 0, sizeof(struct snapshot_handle));
206 		data->ready = 0;
207 		break;
208 
209 	case SNAPSHOT_SET_IMAGE_SIZE:
210 		image_size = arg;
211 		break;
212 
213 	case SNAPSHOT_AVAIL_SWAP:
214 		avail = count_swap_pages(data->swap, 1);
215 		avail <<= PAGE_SHIFT;
216 		error = put_user(avail, (loff_t __user *)arg);
217 		break;
218 
219 	case SNAPSHOT_GET_SWAP_PAGE:
220 		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
221 			error = -ENODEV;
222 			break;
223 		}
224 		if (!data->bitmap) {
225 			data->bitmap = alloc_bitmap(count_swap_pages(data->swap, 0));
226 			if (!data->bitmap) {
227 				error = -ENOMEM;
228 				break;
229 			}
230 		}
231 		offset = alloc_swap_page(data->swap, data->bitmap);
232 		if (offset) {
233 			offset <<= PAGE_SHIFT;
234 			error = put_user(offset, (loff_t __user *)arg);
235 		} else {
236 			error = -ENOSPC;
237 		}
238 		break;
239 
240 	case SNAPSHOT_FREE_SWAP_PAGES:
241 		if (data->swap < 0 || data->swap >= MAX_SWAPFILES) {
242 			error = -ENODEV;
243 			break;
244 		}
245 		free_all_swap_pages(data->swap, data->bitmap);
246 		free_bitmap(data->bitmap);
247 		data->bitmap = NULL;
248 		break;
249 
250 	case SNAPSHOT_SET_SWAP_FILE:
251 		if (!data->bitmap) {
252 			/*
253 			 * User space encodes device types as two-byte values,
254 			 * so we need to recode them
255 			 */
256 			if (old_decode_dev(arg)) {
257 				data->swap = swap_type_of(old_decode_dev(arg));
258 				if (data->swap < 0)
259 					error = -ENODEV;
260 			} else {
261 				data->swap = -1;
262 				error = -EINVAL;
263 			}
264 		} else {
265 			error = -EPERM;
266 		}
267 		break;
268 
269 	case SNAPSHOT_S2RAM:
270 		if (!data->frozen) {
271 			error = -EPERM;
272 			break;
273 		}
274 
275 		if (down_trylock(&pm_sem)) {
276 			error = -EBUSY;
277 			break;
278 		}
279 
280 		if (pm_ops->prepare) {
281 			error = pm_ops->prepare(PM_SUSPEND_MEM);
282 			if (error)
283 				goto OutS3;
284 		}
285 
286 		/* Put devices to sleep */
287 		error = device_suspend(PMSG_SUSPEND);
288 		if (error) {
289 			printk(KERN_ERR "Failed to suspend some devices.\n");
290 		} else {
291 			/* Enter S3, system is already frozen */
292 			suspend_enter(PM_SUSPEND_MEM);
293 
294 			/* Wake up devices */
295 			device_resume();
296 		}
297 
298 		if (pm_ops->finish)
299 			pm_ops->finish(PM_SUSPEND_MEM);
300 
301 OutS3:
302 		up(&pm_sem);
303 		break;
304 
305 	default:
306 		error = -ENOTTY;
307 
308 	}
309 
310 	return error;
311 }
312 
313 static struct file_operations snapshot_fops = {
314 	.open = snapshot_open,
315 	.release = snapshot_release,
316 	.read = snapshot_read,
317 	.write = snapshot_write,
318 	.llseek = no_llseek,
319 	.ioctl = snapshot_ioctl,
320 };
321 
322 static struct miscdevice snapshot_device = {
323 	.minor = SNAPSHOT_MINOR,
324 	.name = "snapshot",
325 	.fops = &snapshot_fops,
326 };
327 
328 static int __init snapshot_device_init(void)
329 {
330 	return misc_register(&snapshot_device);
331 };
332 
333 device_initcall(snapshot_device_init);
334