Merge tag 'v3.10.85' into update
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / power / tuxonice_compress.c
1 /*
2 * kernel/power/compression.c
3 *
4 * Copyright (C) 2003-2010 Nigel Cunningham (nigel at tuxonice net)
5 *
6 * This file is released under the GPLv2.
7 *
8 * This file contains data compression routines for TuxOnIce,
9 * using cryptoapi.
10 */
11
12 #include <linux/suspend.h>
13 #include <linux/highmem.h>
14 #include <linux/vmalloc.h>
15 #include <linux/crypto.h>
16
17 #include "tuxonice_builtin.h"
18 #include "tuxonice.h"
19 #include "tuxonice_modules.h"
20 #include "tuxonice_sysfs.h"
21 #include "tuxonice_io.h"
22 #include "tuxonice_ui.h"
23 #include "tuxonice_alloc.h"
24
25 static int toi_expected_compression;
26 #ifdef CONFIG_TOI_ENHANCE
27 static int toi_actual_compression;
28 #endif
29
30 static struct toi_module_ops toi_compression_ops;
31 static struct toi_module_ops *next_driver;
32
33 static char toi_compressor_name[32] = "lzo";
34
35 static DEFINE_MUTEX(stats_lock);
36
37 struct toi_cpu_context {
38 u8 *page_buffer;
39 struct crypto_comp *transform;
40 unsigned int len;
41 u8 *buffer_start;
42 u8 *output_buffer;
43 };
44
45 #define OUT_BUF_SIZE (2 * PAGE_SIZE)
46
47 static DEFINE_PER_CPU(struct toi_cpu_context, contexts);
48
49 /*
50 * toi_crypto_prepare
51 *
52 * Prepare to do some work by allocating buffers and transforms.
53 */
54 static int toi_compress_crypto_prepare(void)
55 {
56 int cpu;
57
58 if (!*toi_compressor_name) {
59 printk(KERN_INFO "TuxOnIce: Compression enabled but no " "compressor name set.\n");
60 return 1;
61 }
62
63 for_each_online_cpu(cpu) {
64 struct toi_cpu_context *this = &per_cpu(contexts, cpu);
65 this->transform = crypto_alloc_comp(toi_compressor_name, 0, 0);
66 if (IS_ERR(this->transform)) {
67 printk(KERN_INFO "TuxOnIce: Failed to initialise the "
68 "%s compression transform.\n", toi_compressor_name);
69 this->transform = NULL;
70 return 1;
71 }
72
73 this->page_buffer = (char *)toi_get_zeroed_page(16, TOI_ATOMIC_GFP);
74
75 if (!this->page_buffer) {
76 printk(KERN_ERR
77 "Failed to allocate a page buffer for TuxOnIce "
78 "compression driver.\n");
79 return -ENOMEM;
80 }
81
82 this->output_buffer = (char *)vmalloc_32(OUT_BUF_SIZE);
83
84 if (!this->output_buffer) {
85 printk(KERN_ERR
86 "Failed to allocate a output buffer for TuxOnIce "
87 "compression driver.\n");
88 return -ENOMEM;
89 }
90 }
91
92 return 0;
93 }
94
95 static int toi_compress_rw_cleanup(int writing)
96 {
97 int cpu;
98
99 for_each_online_cpu(cpu) {
100 struct toi_cpu_context *this = &per_cpu(contexts, cpu);
101 if (this->transform) {
102 crypto_free_comp(this->transform);
103 this->transform = NULL;
104 }
105
106 if (this->page_buffer)
107 toi_free_page(16, (unsigned long)this->page_buffer);
108
109 this->page_buffer = NULL;
110
111 if (this->output_buffer)
112 vfree(this->output_buffer);
113
114 this->output_buffer = NULL;
115 }
116
117 return 0;
118 }
119
120 /*
121 * toi_compress_init
122 */
123
124 static int toi_compress_init(int toi_or_resume)
125 {
126 if (!toi_or_resume)
127 return 0;
128
129 toi_compress_bytes_in = 0;
130 toi_compress_bytes_out = 0;
131
132 next_driver = toi_get_next_filter(&toi_compression_ops);
133
134 return next_driver ? 0 : -ECHILD;
135 }
136
137 /*
138 * toi_compress_rw_init()
139 */
140
141 static int toi_compress_rw_init(int rw, int stream_number)
142 {
143 if (toi_compress_crypto_prepare()) {
144 printk(KERN_ERR "Failed to initialise compression " "algorithm.\n");
145 if (rw == READ) {
146 printk(KERN_INFO "Unable to read the image.\n");
147 return -ENODEV;
148 } else {
149 printk(KERN_INFO "Continuing without " "compressing the image.\n");
150 toi_compression_ops.enabled = 0;
151 }
152 }
153
154 return 0;
155 }
156
157 /*
158 * toi_compress_write_page()
159 *
160 * Compress a page of data, buffering output and passing on filled
161 * pages to the next module in the pipeline.
162 *
163 * Buffer_page: Pointer to a buffer of size PAGE_SIZE, containing
164 * data to be compressed.
165 *
166 * Returns: 0 on success. Otherwise the error is that returned by later
167 * modules, -ECHILD if we have a broken pipeline or -EIO if
168 * zlib errs.
169 */
170 static int toi_compress_write_page(unsigned long index, int buf_type,
171 void *buffer_page, unsigned int buf_size)
172 {
173 int ret = 0, cpu = smp_processor_id();
174 struct toi_cpu_context *ctx = &per_cpu(contexts, cpu);
175 u8 *output_buffer = buffer_page;
176 int output_len = buf_size;
177 int out_buf_type = buf_type;
178
179 if (ctx->transform) {
180
181 ctx->buffer_start = TOI_MAP(buf_type, buffer_page);
182 ctx->len = OUT_BUF_SIZE;
183
184 ret = crypto_comp_compress(ctx->transform,
185 ctx->buffer_start, buf_size,
186 ctx->output_buffer, &ctx->len);
187
188 TOI_UNMAP(buf_type, buffer_page);
189
190 toi_message(TOI_COMPRESS, TOI_VERBOSE, 0,
191 "CPU %d, index %lu: %d bytes", cpu, index, ctx->len);
192
193 if (!ret && ctx->len < buf_size) { /* some compression */
194 output_buffer = ctx->output_buffer;
195 output_len = ctx->len;
196 out_buf_type = TOI_VIRT;
197 }
198
199 }
200
201 mutex_lock(&stats_lock);
202
203 toi_compress_bytes_in += buf_size;
204 toi_compress_bytes_out += output_len;
205
206 mutex_unlock(&stats_lock);
207
208 if (!ret)
209 ret = next_driver->write_page(index, out_buf_type, output_buffer, output_len);
210
211 return ret;
212 }
213
214 /*
215 * toi_compress_read_page()
216 * @buffer_page: struct page *. Pointer to a buffer of size PAGE_SIZE.
217 *
218 * Retrieve data from later modules and decompress it until the input buffer
219 * is filled.
220 * Zero if successful. Error condition from me or from downstream on failure.
221 */
222 static int toi_compress_read_page(unsigned long *index, int buf_type,
223 void *buffer_page, unsigned int *buf_size)
224 {
225 int ret, cpu = smp_processor_id();
226 unsigned int len;
227 unsigned int outlen = PAGE_SIZE;
228 char *buffer_start;
229 struct toi_cpu_context *ctx = &per_cpu(contexts, cpu);
230
231 if (!ctx->transform)
232 return next_driver->read_page(index, TOI_PAGE, buffer_page, buf_size);
233
234 /*
235 * All our reads must be synchronous - we can't decompress
236 * data that hasn't been read yet.
237 */
238
239 ret = next_driver->read_page(index, TOI_VIRT, ctx->page_buffer, &len);
240
241 buffer_start = kmap(buffer_page);
242
243 /* Error or uncompressed data */
244 if (ret || len == PAGE_SIZE) {
245 memcpy(buffer_start, ctx->page_buffer, len);
246 goto out;
247 }
248
249 ret = crypto_comp_decompress(ctx->transform, ctx->page_buffer, len, buffer_start, &outlen);
250
251 toi_message(TOI_COMPRESS, TOI_VERBOSE, 0,
252 "CPU %d, index %lu: %d=>%d (%d).", cpu, *index, len, outlen, ret);
253
254 if (ret)
255 abort_hibernate(TOI_FAILED_IO, "Compress_read returned %d.\n", ret);
256 else if (outlen != PAGE_SIZE) {
257 abort_hibernate(TOI_FAILED_IO,
258 "Decompression yielded %d bytes instead of %ld.\n",
259 outlen, PAGE_SIZE);
260 printk(KERN_ERR "Decompression yielded %d bytes instead of "
261 "%ld.\n", outlen, PAGE_SIZE);
262 ret = -EIO;
263 *buf_size = outlen;
264 }
265 out:
266 TOI_UNMAP(buf_type, buffer_page);
267 return ret;
268 }
269
270 /*
271 * toi_compress_print_debug_stats
272 * @buffer: Pointer to a buffer into which the debug info will be printed.
273 * @size: Size of the buffer.
274 *
275 * Print information to be recorded for debugging purposes into a buffer.
276 * Returns: Number of characters written to the buffer.
277 */
278
279 static int toi_compress_print_debug_stats(char *buffer, int size)
280 {
281 unsigned long pages_in = toi_compress_bytes_in >> PAGE_SHIFT,
282 pages_out = toi_compress_bytes_out >> PAGE_SHIFT;
283 int len;
284
285 /* Output the compression ratio achieved. */
286 if (*toi_compressor_name)
287 len = scnprintf(buffer, size, "- Compressor is '%s'.\n", toi_compressor_name);
288 else
289 len = scnprintf(buffer, size, "- Compressor is not set.\n");
290
291 if (pages_in)
292 len += scnprintf(buffer + len, size - len, " Compressed "
293 "%lu bytes into %lu (%ld percent compression).\n",
294 toi_compress_bytes_in,
295 toi_compress_bytes_out, (pages_in - pages_out) * 100 / pages_in);
296 return len;
297 }
298
299 /*
300 * toi_compress_compression_memory_needed
301 *
302 * Tell the caller how much memory we need to operate during hibernate/resume.
303 * Returns: Unsigned long. Maximum number of bytes of memory required for
304 * operation.
305 */
306 static int toi_compress_memory_needed(void)
307 {
308 return 2 * PAGE_SIZE;
309 }
310
311 static int toi_compress_storage_needed(void)
312 {
313 return 2 * sizeof(unsigned long) + 2 * sizeof(int) + strlen(toi_compressor_name) + 1;
314 }
315
316 /*
317 * toi_compress_save_config_info
318 * @buffer: Pointer to a buffer of size PAGE_SIZE.
319 *
320 * Save informaton needed when reloading the image at resume time.
321 * Returns: Number of bytes used for saving our data.
322 */
323 static int toi_compress_save_config_info(char *buffer)
324 {
325 int len = strlen(toi_compressor_name) + 1, offset = 0;
326
327 *((unsigned long *)buffer) = toi_compress_bytes_in;
328 offset += sizeof(unsigned long);
329 *((unsigned long *)(buffer + offset)) = toi_compress_bytes_out;
330 offset += sizeof(unsigned long);
331 *((int *)(buffer + offset)) = toi_expected_compression;
332 offset += sizeof(int);
333 *((int *)(buffer + offset)) = len;
334 offset += sizeof(int);
335 strncpy(buffer + offset, toi_compressor_name, len);
336 return offset + len;
337 }
338
339 /* toi_compress_load_config_info
340 * @buffer: Pointer to the start of the data.
341 * @size: Number of bytes that were saved.
342 *
343 * Description: Reload information needed for decompressing the image at
344 * resume time.
345 */
346 static void toi_compress_load_config_info(char *buffer, int size)
347 {
348 int len, offset = 0;
349
350 toi_compress_bytes_in = *((unsigned long *)buffer);
351 offset += sizeof(unsigned long);
352 toi_compress_bytes_out = *((unsigned long *)(buffer + offset));
353 offset += sizeof(unsigned long);
354 toi_expected_compression = *((int *)(buffer + offset));
355 offset += sizeof(int);
356 len = *((int *)(buffer + offset));
357 offset += sizeof(int);
358 strncpy(toi_compressor_name, buffer + offset, len);
359 }
360
361 static void toi_compress_pre_atomic_restore(struct toi_boot_kernel_data *bkd)
362 {
363 bkd->compress_bytes_in = toi_compress_bytes_in;
364 bkd->compress_bytes_out = toi_compress_bytes_out;
365 }
366
367 static void toi_compress_post_atomic_restore(struct toi_boot_kernel_data *bkd)
368 {
369 toi_compress_bytes_in = bkd->compress_bytes_in;
370 toi_compress_bytes_out = bkd->compress_bytes_out;
371 }
372
373 /*
374 * toi_expected_compression_ratio
375 *
376 * Description: Returns the expected ratio between data passed into this module
377 * and the amount of data output when writing.
378 * Returns: 100 if the module is disabled. Otherwise the value set by the
379 * user via our sysfs entry.
380 */
381
382 static int toi_compress_expected_ratio(void)
383 {
384 if (!toi_compression_ops.enabled)
385 return 100;
386 else
387 return 100 - toi_expected_compression;
388 }
389
390 #ifdef CONFIG_TOI_ENHANCE
391 /*
392 * toi_actual_compression_ratio
393 *
394 * Description: Returns the actual ratio of the lastest compression result.
395 * Returns: 0 if the module is disabled.
396 */
397 static int toi_compress_actual_ratio(void)
398 {
399 unsigned long pages_in = toi_compress_bytes_in >> PAGE_SHIFT,
400 pages_out = toi_compress_bytes_out >> PAGE_SHIFT;
401
402 toi_actual_compression = 0;
403 if (!toi_compression_ops.enabled)
404 toi_actual_compression = 0;
405 else if (pages_in > 0 && (pages_in - pages_out >= 0))
406 toi_actual_compression = (pages_in - pages_out) * 100 / pages_in;
407
408 pr_warn("[%s] actual compressed ratio %d (%lu/%lu)\n", __func__,
409 toi_actual_compression, pages_in, pages_out);
410 return toi_actual_compression;
411 }
412 #endif
413
414 /*
415 * data for our sysfs entries.
416 */
417 static struct toi_sysfs_data sysfs_params[] = {
418 SYSFS_INT("expected_compression", SYSFS_RW, &toi_expected_compression,
419 0, 99, 0, NULL),
420 SYSFS_INT("enabled", SYSFS_RW, &toi_compression_ops.enabled, 0, 1, 0,
421 NULL),
422 SYSFS_STRING("algorithm", SYSFS_RW, toi_compressor_name, 31, 0, NULL),
423 #ifdef CONFIG_TOI_ENHANCE
424 SYSFS_INT("actual_compression", SYSFS_READONLY, &toi_actual_compression,
425 0, 99, 0, NULL),
426 #endif
427 };
428
429 /*
430 * Ops structure.
431 */
432 static struct toi_module_ops toi_compression_ops = {
433 .type = FILTER_MODULE,
434 .name = "compression",
435 .directory = "compression",
436 .module = THIS_MODULE,
437 .initialise = toi_compress_init,
438 .memory_needed = toi_compress_memory_needed,
439 .print_debug_info = toi_compress_print_debug_stats,
440 .save_config_info = toi_compress_save_config_info,
441 .load_config_info = toi_compress_load_config_info,
442 .storage_needed = toi_compress_storage_needed,
443 .expected_compression = toi_compress_expected_ratio,
444 #ifdef CONFIG_TOI_ENHANCE
445 .actual_compression = toi_compress_actual_ratio,
446 #endif
447
448 .pre_atomic_restore = toi_compress_pre_atomic_restore,
449 .post_atomic_restore = toi_compress_post_atomic_restore,
450
451 .rw_init = toi_compress_rw_init,
452 .rw_cleanup = toi_compress_rw_cleanup,
453
454 .write_page = toi_compress_write_page,
455 .read_page = toi_compress_read_page,
456
457 .sysfs_data = sysfs_params,
458 .num_sysfs_entries = sizeof(sysfs_params) / sizeof(struct toi_sysfs_data),
459 };
460
461 /* ---- Registration ---- */
462
463 static __init int toi_compress_load(void)
464 {
465 return toi_register_module(&toi_compression_ops);
466 }
467
468 #ifdef MODULE
469 static __exit void toi_compress_unload(void)
470 {
471 toi_unregister_module(&toi_compression_ops);
472 }
473 module_init(toi_compress_load);
474 module_exit(toi_compress_unload);
475 MODULE_LICENSE("GPL");
476 MODULE_AUTHOR("Nigel Cunningham");
477 MODULE_DESCRIPTION("Compression Support for TuxOnIce");
478 #else
479 late_initcall(toi_compress_load);
480 #endif