aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/misc/ramoops.txt48
-rw-r--r--Documentation/ramoops.txt6
-rw-r--r--arch/powerpc/kernel/nvram_64.c4
-rw-r--r--drivers/acpi/apei/erst.c7
-rw-r--r--drivers/firmware/efi/efi-pstore.c13
-rw-r--r--fs/pstore/Kconfig31
-rw-r--r--fs/pstore/inode.c1
-rw-r--r--fs/pstore/platform.c269
-rw-r--r--fs/pstore/ram.c105
-rw-r--r--include/linux/pstore.h3
10 files changed, 436 insertions, 51 deletions
diff --git a/Documentation/devicetree/bindings/misc/ramoops.txt b/Documentation/devicetree/bindings/misc/ramoops.txt
new file mode 100644
index 000000000000..cd02cec67d38
--- /dev/null
+++ b/Documentation/devicetree/bindings/misc/ramoops.txt
@@ -0,0 +1,48 @@
1Ramoops oops/panic logger
2=========================
3
4ramoops provides persistent RAM storage for oops and panics, so they can be
5recovered after a reboot. It is a backend to pstore, so this node is named
6"ramoops" after the backend, rather than "pstore" which is the subsystem.
7
8Parts of this storage may be set aside for other persistent log buffers, such
9as kernel log messages, or for optional ECC error-correction data. The total
10size of these optional buffers must fit in the reserved region.
11
12Any remaining space will be used for a circular buffer of oops and panic
13records. These records have a configurable size, with a size of 0 indicating
14that they should be disabled.
15
16At least one of "record-size", "console-size", "ftrace-size", or "pmsg-size"
17must be set non-zero, but are otherwise optional as listed below.
18
19
20Required properties:
21
22- compatible: must be "ramoops"
23
24- memory-region: phandle to a region of memory that is preserved between
25 reboots
26
27
28Optional properties:
29
30- ecc-size: enables ECC support and specifies ECC buffer size in bytes
31 (defaults to 0: no ECC)
32
33- record-size: maximum size in bytes of each dump done on oops/panic
34 (defaults to 0: disabled)
35
36- console-size: size in bytes of log buffer reserved for kernel messages
37 (defaults to 0: disabled)
38
39- ftrace-size: size in bytes of log buffer reserved for function tracing and
40 profiling (defaults to 0: disabled)
41
42- pmsg-size: size in bytes of log buffer reserved for userspace messages
43 (defaults to 0: disabled)
44
45- unbuffered: if present, use unbuffered mappings to map the reserved region
46 (defaults to buffered mappings)
47
48- no-dump-oops: if present, only dump panics (defaults to panics and oops)
diff --git a/Documentation/ramoops.txt b/Documentation/ramoops.txt
index 5d8675615e59..9264bcab4099 100644
--- a/Documentation/ramoops.txt
+++ b/Documentation/ramoops.txt
@@ -45,7 +45,7 @@ corrupt, but usually it is restorable.
45 45
462. Setting the parameters 462. Setting the parameters
47 47
48Setting the ramoops parameters can be done in 2 different manners: 48Setting the ramoops parameters can be done in 3 different manners:
49 1. Use the module parameters (which have the names of the variables described 49 1. Use the module parameters (which have the names of the variables described
50 as before). 50 as before).
51 For quick debugging, you can also reserve parts of memory during boot 51 For quick debugging, you can also reserve parts of memory during boot
@@ -54,7 +54,9 @@ Setting the ramoops parameters can be done in 2 different manners:
54 kernel to use only the first 128 MB of memory, and place ECC-protected ramoops 54 kernel to use only the first 128 MB of memory, and place ECC-protected ramoops
55 region at 128 MB boundary: 55 region at 128 MB boundary:
56 "mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1" 56 "mem=128M ramoops.mem_address=0x8000000 ramoops.ecc=1"
57 2. Use a platform device and set the platform data. The parameters can then 57 2. Use Device Tree bindings, as described in
58 Documentation/device-tree/bindings/misc/ramoops.txt.
59 3. Use a platform device and set the platform data. The parameters can then
58 be set through that platform data. An example of doing that is: 60 be set through that platform data. An example of doing that is:
59 61
60#include <linux/pstore_ram.h> 62#include <linux/pstore_ram.h>
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 856f9a7944cd..64174bf95611 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -444,7 +444,8 @@ static int nvram_pstore_write(enum pstore_type_id type,
444 */ 444 */
445static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type, 445static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
446 int *count, struct timespec *time, char **buf, 446 int *count, struct timespec *time, char **buf,
447 bool *compressed, struct pstore_info *psi) 447 bool *compressed, ssize_t *ecc_notice_size,
448 struct pstore_info *psi)
448{ 449{
449 struct oops_log_info *oops_hdr; 450 struct oops_log_info *oops_hdr;
450 unsigned int err_type, id_no, size = 0; 451 unsigned int err_type, id_no, size = 0;
@@ -545,6 +546,7 @@ static ssize_t nvram_pstore_read(u64 *id, enum pstore_type_id *type,
545 return -ENOMEM; 546 return -ENOMEM;
546 kfree(buff); 547 kfree(buff);
547 548
549 *ecc_notice_size = 0;
548 if (err_type == ERR_TYPE_KERNEL_PANIC_GZ) 550 if (err_type == ERR_TYPE_KERNEL_PANIC_GZ)
549 *compressed = true; 551 *compressed = true;
550 else 552 else
diff --git a/drivers/acpi/apei/erst.c b/drivers/acpi/apei/erst.c
index 006c3894c6ea..f096ab3cb54d 100644
--- a/drivers/acpi/apei/erst.c
+++ b/drivers/acpi/apei/erst.c
@@ -927,7 +927,8 @@ static int erst_open_pstore(struct pstore_info *psi);
927static int erst_close_pstore(struct pstore_info *psi); 927static int erst_close_pstore(struct pstore_info *psi);
928static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, 928static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
929 struct timespec *time, char **buf, 929 struct timespec *time, char **buf,
930 bool *compressed, struct pstore_info *psi); 930 bool *compressed, ssize_t *ecc_notice_size,
931 struct pstore_info *psi);
931static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason, 932static int erst_writer(enum pstore_type_id type, enum kmsg_dump_reason reason,
932 u64 *id, unsigned int part, int count, bool compressed, 933 u64 *id, unsigned int part, int count, bool compressed,
933 size_t size, struct pstore_info *psi); 934 size_t size, struct pstore_info *psi);
@@ -987,7 +988,8 @@ static int erst_close_pstore(struct pstore_info *psi)
987 988
988static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count, 989static ssize_t erst_reader(u64 *id, enum pstore_type_id *type, int *count,
989 struct timespec *time, char **buf, 990 struct timespec *time, char **buf,
990 bool *compressed, struct pstore_info *psi) 991 bool *compressed, ssize_t *ecc_notice_size,
992 struct pstore_info *psi)
991{ 993{
992 int rc; 994 int rc;
993 ssize_t len = 0; 995 ssize_t len = 0;
@@ -1033,6 +1035,7 @@ skip:
1033 memcpy(*buf, rcd->data, len - sizeof(*rcd)); 1035 memcpy(*buf, rcd->data, len - sizeof(*rcd));
1034 *id = record_id; 1036 *id = record_id;
1035 *compressed = false; 1037 *compressed = false;
1038 *ecc_notice_size = 0;
1036 if (uuid_le_cmp(rcd->sec_hdr.section_type, 1039 if (uuid_le_cmp(rcd->sec_hdr.section_type,
1037 CPER_SECTION_TYPE_DMESG_Z) == 0) { 1040 CPER_SECTION_TYPE_DMESG_Z) == 0) {
1038 *type = PSTORE_TYPE_DMESG; 1041 *type = PSTORE_TYPE_DMESG;
diff --git a/drivers/firmware/efi/efi-pstore.c b/drivers/firmware/efi/efi-pstore.c
index eac76a79a880..30a24d09ea6c 100644
--- a/drivers/firmware/efi/efi-pstore.c
+++ b/drivers/firmware/efi/efi-pstore.c
@@ -34,6 +34,7 @@ struct pstore_read_data {
34 int *count; 34 int *count;
35 struct timespec *timespec; 35 struct timespec *timespec;
36 bool *compressed; 36 bool *compressed;
37 ssize_t *ecc_notice_size;
37 char **buf; 38 char **buf;
38}; 39};
39 40
@@ -69,6 +70,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
69 *cb_data->compressed = true; 70 *cb_data->compressed = true;
70 else 71 else
71 *cb_data->compressed = false; 72 *cb_data->compressed = false;
73 *cb_data->ecc_notice_size = 0;
72 } else if (sscanf(name, "dump-type%u-%u-%d-%lu", 74 } else if (sscanf(name, "dump-type%u-%u-%d-%lu",
73 cb_data->type, &part, &cnt, &time) == 4) { 75 cb_data->type, &part, &cnt, &time) == 4) {
74 *cb_data->id = generic_id(time, part, cnt); 76 *cb_data->id = generic_id(time, part, cnt);
@@ -76,6 +78,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
76 cb_data->timespec->tv_sec = time; 78 cb_data->timespec->tv_sec = time;
77 cb_data->timespec->tv_nsec = 0; 79 cb_data->timespec->tv_nsec = 0;
78 *cb_data->compressed = false; 80 *cb_data->compressed = false;
81 *cb_data->ecc_notice_size = 0;
79 } else if (sscanf(name, "dump-type%u-%u-%lu", 82 } else if (sscanf(name, "dump-type%u-%u-%lu",
80 cb_data->type, &part, &time) == 3) { 83 cb_data->type, &part, &time) == 3) {
81 /* 84 /*
@@ -88,6 +91,7 @@ static int efi_pstore_read_func(struct efivar_entry *entry, void *data)
88 cb_data->timespec->tv_sec = time; 91 cb_data->timespec->tv_sec = time;
89 cb_data->timespec->tv_nsec = 0; 92 cb_data->timespec->tv_nsec = 0;
90 *cb_data->compressed = false; 93 *cb_data->compressed = false;
94 *cb_data->ecc_notice_size = 0;
91 } else 95 } else
92 return 0; 96 return 0;
93 97
@@ -210,6 +214,7 @@ static int efi_pstore_sysfs_entry_iter(void *data, struct efivar_entry **pos)
210static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type, 214static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
211 int *count, struct timespec *timespec, 215 int *count, struct timespec *timespec,
212 char **buf, bool *compressed, 216 char **buf, bool *compressed,
217 ssize_t *ecc_notice_size,
213 struct pstore_info *psi) 218 struct pstore_info *psi)
214{ 219{
215 struct pstore_read_data data; 220 struct pstore_read_data data;
@@ -220,6 +225,7 @@ static ssize_t efi_pstore_read(u64 *id, enum pstore_type_id *type,
220 data.count = count; 225 data.count = count;
221 data.timespec = timespec; 226 data.timespec = timespec;
222 data.compressed = compressed; 227 data.compressed = compressed;
228 data.ecc_notice_size = ecc_notice_size;
223 data.buf = buf; 229 data.buf = buf;
224 230
225 *data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL); 231 *data.buf = kzalloc(EFIVARS_DATA_SIZE_MAX, GFP_KERNEL);
@@ -393,6 +399,13 @@ static __init int efivars_pstore_init(void)
393 399
394static __exit void efivars_pstore_exit(void) 400static __exit void efivars_pstore_exit(void)
395{ 401{
402 if (!efi_pstore_info.bufsize)
403 return;
404
405 pstore_unregister(&efi_pstore_info);
406 kfree(efi_pstore_info.buf);
407 efi_pstore_info.buf = NULL;
408 efi_pstore_info.bufsize = 0;
396} 409}
397 410
398module_init(efivars_pstore_init); 411module_init(efivars_pstore_init);
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 360ae43f590c..be40813eff52 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -1,8 +1,6 @@
1config PSTORE 1config PSTORE
2 tristate "Persistent store support" 2 tristate "Persistent store support"
3 default n 3 default n
4 select ZLIB_DEFLATE
5 select ZLIB_INFLATE
6 help 4 help
7 This option enables generic access to platform level 5 This option enables generic access to platform level
8 persistent storage via "pstore" filesystem that can 6 persistent storage via "pstore" filesystem that can
@@ -14,6 +12,35 @@ config PSTORE
14 If you don't have a platform persistent store driver, 12 If you don't have a platform persistent store driver,
15 say N. 13 say N.
16 14
15choice
16 prompt "Choose compression algorithm"
17 depends on PSTORE
18 default PSTORE_ZLIB_COMPRESS
19 help
20 This option chooses compression algorithm.
21
22config PSTORE_ZLIB_COMPRESS
23 bool "ZLIB"
24 select ZLIB_DEFLATE
25 select ZLIB_INFLATE
26 help
27 This option enables ZLIB compression algorithm support.
28
29config PSTORE_LZO_COMPRESS
30 bool "LZO"
31 select LZO_COMPRESS
32 select LZO_DECOMPRESS
33 help
34 This option enables LZO compression algorithm support.
35
36config PSTORE_LZ4_COMPRESS
37 bool "LZ4"
38 select LZ4_COMPRESS
39 select LZ4_DECOMPRESS
40 help
41 This option enables LZ4 compression algorithm support.
42endchoice
43
17config PSTORE_CONSOLE 44config PSTORE_CONSOLE
18 bool "Log kernel console messages" 45 bool "Log kernel console messages"
19 depends on PSTORE 46 depends on PSTORE
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 45d6110744cb..ec9ddef5ae75 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -178,7 +178,6 @@ static loff_t pstore_file_llseek(struct file *file, loff_t off, int whence)
178} 178}
179 179
180static const struct file_operations pstore_file_operations = { 180static const struct file_operations pstore_file_operations = {
181 .owner = THIS_MODULE,
182 .open = pstore_file_open, 181 .open = pstore_file_open,
183 .read = pstore_file_read, 182 .read = pstore_file_read,
184 .llseek = pstore_file_llseek, 183 .llseek = pstore_file_llseek,
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 588461bb2dd4..16ecca5b72d8 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -28,7 +28,15 @@
28#include <linux/console.h> 28#include <linux/console.h>
29#include <linux/module.h> 29#include <linux/module.h>
30#include <linux/pstore.h> 30#include <linux/pstore.h>
31#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
31#include <linux/zlib.h> 32#include <linux/zlib.h>
33#endif
34#ifdef CONFIG_PSTORE_LZO_COMPRESS
35#include <linux/lzo.h>
36#endif
37#ifdef CONFIG_PSTORE_LZ4_COMPRESS
38#include <linux/lz4.h>
39#endif
32#include <linux/string.h> 40#include <linux/string.h>
33#include <linux/timer.h> 41#include <linux/timer.h>
34#include <linux/slab.h> 42#include <linux/slab.h>
@@ -69,10 +77,23 @@ struct pstore_info *psinfo;
69static char *backend; 77static char *backend;
70 78
71/* Compression parameters */ 79/* Compression parameters */
80#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
72#define COMPR_LEVEL 6 81#define COMPR_LEVEL 6
73#define WINDOW_BITS 12 82#define WINDOW_BITS 12
74#define MEM_LEVEL 4 83#define MEM_LEVEL 4
75static struct z_stream_s stream; 84static struct z_stream_s stream;
85#else
86static unsigned char *workspace;
87#endif
88
89struct pstore_zbackend {
90 int (*compress)(const void *in, void *out, size_t inlen, size_t outlen);
91 int (*decompress)(void *in, void *out, size_t inlen, size_t outlen);
92 void (*allocate)(void);
93 void (*free)(void);
94
95 const char *name;
96};
76 97
77static char *big_oops_buf; 98static char *big_oops_buf;
78static size_t big_oops_buf_sz; 99static size_t big_oops_buf_sz;
@@ -129,9 +150,9 @@ bool pstore_cannot_block_path(enum kmsg_dump_reason reason)
129} 150}
130EXPORT_SYMBOL_GPL(pstore_cannot_block_path); 151EXPORT_SYMBOL_GPL(pstore_cannot_block_path);
131 152
153#ifdef CONFIG_PSTORE_ZLIB_COMPRESS
132/* Derived from logfs_compress() */ 154/* Derived from logfs_compress() */
133static int pstore_compress(const void *in, void *out, size_t inlen, 155static int compress_zlib(const void *in, void *out, size_t inlen, size_t outlen)
134 size_t outlen)
135{ 156{
136 int err, ret; 157 int err, ret;
137 158
@@ -165,7 +186,7 @@ error:
165} 186}
166 187
167/* Derived from logfs_uncompress */ 188/* Derived from logfs_uncompress */
168static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen) 189static int decompress_zlib(void *in, void *out, size_t inlen, size_t outlen)
169{ 190{
170 int err, ret; 191 int err, ret;
171 192
@@ -194,7 +215,7 @@ error:
194 return ret; 215 return ret;
195} 216}
196 217
197static void allocate_buf_for_compression(void) 218static void allocate_zlib(void)
198{ 219{
199 size_t size; 220 size_t size;
200 size_t cmpr; 221 size_t cmpr;
@@ -237,12 +258,190 @@ static void allocate_buf_for_compression(void)
237 258
238} 259}
239 260
240static void free_buf_for_compression(void) 261static void free_zlib(void)
241{ 262{
242 kfree(stream.workspace); 263 kfree(stream.workspace);
243 stream.workspace = NULL; 264 stream.workspace = NULL;
244 kfree(big_oops_buf); 265 kfree(big_oops_buf);
245 big_oops_buf = NULL; 266 big_oops_buf = NULL;
267 big_oops_buf_sz = 0;
268}
269
270static struct pstore_zbackend backend_zlib = {
271 .compress = compress_zlib,
272 .decompress = decompress_zlib,
273 .allocate = allocate_zlib,
274 .free = free_zlib,
275 .name = "zlib",
276};
277#endif
278
279#ifdef CONFIG_PSTORE_LZO_COMPRESS
280static int compress_lzo(const void *in, void *out, size_t inlen, size_t outlen)
281{
282 int ret;
283
284 ret = lzo1x_1_compress(in, inlen, out, &outlen, workspace);
285 if (ret != LZO_E_OK) {
286 pr_err("lzo_compress error, ret = %d!\n", ret);
287 return -EIO;
288 }
289
290 return outlen;
291}
292
293static int decompress_lzo(void *in, void *out, size_t inlen, size_t outlen)
294{
295 int ret;
296
297 ret = lzo1x_decompress_safe(in, inlen, out, &outlen);
298 if (ret != LZO_E_OK) {
299 pr_err("lzo_decompress error, ret = %d!\n", ret);
300 return -EIO;
301 }
302
303 return outlen;
304}
305
306static void allocate_lzo(void)
307{
308 big_oops_buf_sz = lzo1x_worst_compress(psinfo->bufsize);
309 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
310 if (big_oops_buf) {
311 workspace = kmalloc(LZO1X_MEM_COMPRESS, GFP_KERNEL);
312 if (!workspace) {
313 pr_err("No memory for compression workspace; skipping compression\n");
314 kfree(big_oops_buf);
315 big_oops_buf = NULL;
316 }
317 } else {
318 pr_err("No memory for uncompressed data; skipping compression\n");
319 workspace = NULL;
320 }
321}
322
323static void free_lzo(void)
324{
325 kfree(workspace);
326 kfree(big_oops_buf);
327 big_oops_buf = NULL;
328 big_oops_buf_sz = 0;
329}
330
331static struct pstore_zbackend backend_lzo = {
332 .compress = compress_lzo,
333 .decompress = decompress_lzo,
334 .allocate = allocate_lzo,
335 .free = free_lzo,
336 .name = "lzo",
337};
338#endif
339
340#ifdef CONFIG_PSTORE_LZ4_COMPRESS
341static int compress_lz4(const void *in, void *out, size_t inlen, size_t outlen)
342{
343 int ret;
344
345 ret = lz4_compress(in, inlen, out, &outlen, workspace);
346 if (ret) {
347 pr_err("lz4_compress error, ret = %d!\n", ret);
348 return -EIO;
349 }
350
351 return outlen;
352}
353
354static int decompress_lz4(void *in, void *out, size_t inlen, size_t outlen)
355{
356 int ret;
357
358 ret = lz4_decompress_unknownoutputsize(in, inlen, out, &outlen);
359 if (ret) {
360 pr_err("lz4_decompress error, ret = %d!\n", ret);
361 return -EIO;
362 }
363
364 return outlen;
365}
366
367static void allocate_lz4(void)
368{
369 big_oops_buf_sz = lz4_compressbound(psinfo->bufsize);
370 big_oops_buf = kmalloc(big_oops_buf_sz, GFP_KERNEL);
371 if (big_oops_buf) {
372 workspace = kmalloc(LZ4_MEM_COMPRESS, GFP_KERNEL);
373 if (!workspace) {
374 pr_err("No memory for compression workspace; skipping compression\n");
375 kfree(big_oops_buf);
376 big_oops_buf = NULL;
377 }
378 } else {
379 pr_err("No memory for uncompressed data; skipping compression\n");
380 workspace = NULL;
381 }
382}
383
384static void free_lz4(void)
385{
386 kfree(workspace);
387 kfree(big_oops_buf);
388 big_oops_buf = NULL;
389 big_oops_buf_sz = 0;
390}
391
392static struct pstore_zbackend backend_lz4 = {
393 .compress = compress_lz4,
394 .decompress = decompress_lz4,
395 .allocate = allocate_lz4,
396 .free = free_lz4,
397 .name = "lz4",
398};
399#endif
400
401static struct pstore_zbackend *zbackend =
402#if defined(CONFIG_PSTORE_ZLIB_COMPRESS)
403 &backend_zlib;
404#elif defined(CONFIG_PSTORE_LZO_COMPRESS)
405 &backend_lzo;
406#elif defined(CONFIG_PSTORE_LZ4_COMPRESS)
407 &backend_lz4;
408#else
409 NULL;
410#endif
411
412static int pstore_compress(const void *in, void *out,
413 size_t inlen, size_t outlen)
414{
415 if (zbackend)
416 return zbackend->compress(in, out, inlen, outlen);
417 else
418 return -EIO;
419}
420
421static int pstore_decompress(void *in, void *out, size_t inlen, size_t outlen)
422{
423 if (zbackend)
424 return zbackend->decompress(in, out, inlen, outlen);
425 else
426 return -EIO;
427}
428
429static void allocate_buf_for_compression(void)
430{
431 if (zbackend) {
432 pr_info("using %s compression\n", zbackend->name);
433 zbackend->allocate();
434 } else {
435 pr_err("allocate compression buffer error!\n");
436 }
437}
438
439static void free_buf_for_compression(void)
440{
441 if (zbackend)
442 zbackend->free();
443 else
444 pr_err("free compression buffer error!\n");
246} 445}
247 446
248/* 447/*
@@ -284,7 +483,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
284 u64 id; 483 u64 id;
285 unsigned int part = 1; 484 unsigned int part = 1;
286 unsigned long flags = 0; 485 unsigned long flags = 0;
287 int is_locked = 0; 486 int is_locked;
288 int ret; 487 int ret;
289 488
290 why = get_reason_str(reason); 489 why = get_reason_str(reason);
@@ -295,8 +494,10 @@ static void pstore_dump(struct kmsg_dumper *dumper,
295 pr_err("pstore dump routine blocked in %s path, may corrupt error record\n" 494 pr_err("pstore dump routine blocked in %s path, may corrupt error record\n"
296 , in_nmi() ? "NMI" : why); 495 , in_nmi() ? "NMI" : why);
297 } 496 }
298 } else 497 } else {
299 spin_lock_irqsave(&psinfo->buf_lock, flags); 498 spin_lock_irqsave(&psinfo->buf_lock, flags);
499 is_locked = 1;
500 }
300 oopscount++; 501 oopscount++;
301 while (total < kmsg_bytes) { 502 while (total < kmsg_bytes) {
302 char *dst; 503 char *dst;
@@ -304,19 +505,25 @@ static void pstore_dump(struct kmsg_dumper *dumper,
304 int hsize; 505 int hsize;
305 int zipped_len = -1; 506 int zipped_len = -1;
306 size_t len; 507 size_t len;
307 bool compressed; 508 bool compressed = false;
308 size_t total_len; 509 size_t total_len;
309 510
310 if (big_oops_buf && is_locked) { 511 if (big_oops_buf && is_locked) {
311 dst = big_oops_buf; 512 dst = big_oops_buf;
312 hsize = sprintf(dst, "%s#%d Part%u\n", why, 513 size = big_oops_buf_sz;
313 oopscount, part); 514 } else {
314 size = big_oops_buf_sz - hsize; 515 dst = psinfo->buf;
516 size = psinfo->bufsize;
517 }
315 518
316 if (!kmsg_dump_get_buffer(dumper, true, dst + hsize, 519 hsize = sprintf(dst, "%s#%d Part%u\n", why, oopscount, part);
317 size, &len)) 520 size -= hsize;
318 break; 521
522 if (!kmsg_dump_get_buffer(dumper, true, dst + hsize,
523 size, &len))
524 break;
319 525
526 if (big_oops_buf && is_locked) {
320 zipped_len = pstore_compress(dst, psinfo->buf, 527 zipped_len = pstore_compress(dst, psinfo->buf,
321 hsize + len, psinfo->bufsize); 528 hsize + len, psinfo->bufsize);
322 529
@@ -324,21 +531,9 @@ static void pstore_dump(struct kmsg_dumper *dumper,
324 compressed = true; 531 compressed = true;
325 total_len = zipped_len; 532 total_len = zipped_len;
326 } else { 533 } else {
327 compressed = false;
328 total_len = copy_kmsg_to_buffer(hsize, len); 534 total_len = copy_kmsg_to_buffer(hsize, len);
329 } 535 }
330 } else { 536 } else {
331 dst = psinfo->buf;
332 hsize = sprintf(dst, "%s#%d Part%u\n", why, oopscount,
333 part);
334 size = psinfo->bufsize - hsize;
335 dst += hsize;
336
337 if (!kmsg_dump_get_buffer(dumper, true, dst,
338 size, &len))
339 break;
340
341 compressed = false;
342 total_len = hsize + len; 537 total_len = hsize + len;
343 } 538 }
344 539
@@ -350,10 +545,7 @@ static void pstore_dump(struct kmsg_dumper *dumper,
350 total += total_len; 545 total += total_len;
351 part++; 546 part++;
352 } 547 }
353 if (pstore_cannot_block_path(reason)) { 548 if (is_locked)
354 if (is_locked)
355 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
356 } else
357 spin_unlock_irqrestore(&psinfo->buf_lock, flags); 549 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
358} 550}
359 551
@@ -497,9 +689,11 @@ EXPORT_SYMBOL_GPL(pstore_register);
497 689
498void pstore_unregister(struct pstore_info *psi) 690void pstore_unregister(struct pstore_info *psi)
499{ 691{
500 pstore_unregister_pmsg(); 692 if ((psi->flags & PSTORE_FLAGS_FRAGILE) == 0) {
501 pstore_unregister_ftrace(); 693 pstore_unregister_pmsg();
502 pstore_unregister_console(); 694 pstore_unregister_ftrace();
695 pstore_unregister_console();
696 }
503 pstore_unregister_kmsg(); 697 pstore_unregister_kmsg();
504 698
505 free_buf_for_compression(); 699 free_buf_for_compression();
@@ -527,6 +721,7 @@ void pstore_get_records(int quiet)
527 int failed = 0, rc; 721 int failed = 0, rc;
528 bool compressed; 722 bool compressed;
529 int unzipped_len = -1; 723 int unzipped_len = -1;
724 ssize_t ecc_notice_size = 0;
530 725
531 if (!psi) 726 if (!psi)
532 return; 727 return;
@@ -536,7 +731,7 @@ void pstore_get_records(int quiet)
536 goto out; 731 goto out;
537 732
538 while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed, 733 while ((size = psi->read(&id, &type, &count, &time, &buf, &compressed,
539 psi)) > 0) { 734 &ecc_notice_size, psi)) > 0) {
540 if (compressed && (type == PSTORE_TYPE_DMESG)) { 735 if (compressed && (type == PSTORE_TYPE_DMESG)) {
541 if (big_oops_buf) 736 if (big_oops_buf)
542 unzipped_len = pstore_decompress(buf, 737 unzipped_len = pstore_decompress(buf,
@@ -544,6 +739,9 @@ void pstore_get_records(int quiet)
544 big_oops_buf_sz); 739 big_oops_buf_sz);
545 740
546 if (unzipped_len > 0) { 741 if (unzipped_len > 0) {
742 if (ecc_notice_size)
743 memcpy(big_oops_buf + unzipped_len,
744 buf + size, ecc_notice_size);
547 kfree(buf); 745 kfree(buf);
548 buf = big_oops_buf; 746 buf = big_oops_buf;
549 size = unzipped_len; 747 size = unzipped_len;
@@ -555,7 +753,8 @@ void pstore_get_records(int quiet)
555 } 753 }
556 } 754 }
557 rc = pstore_mkfile(type, psi->name, id, count, buf, 755 rc = pstore_mkfile(type, psi->name, id, count, buf,
558 compressed, (size_t)size, time, psi); 756 compressed, size + ecc_notice_size,
757 time, psi);
559 if (unzipped_len < 0) { 758 if (unzipped_len < 0) {
560 /* Free buffer other than big oops */ 759 /* Free buffer other than big oops */
561 kfree(buf); 760 kfree(buf);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index bd9812e83461..47516a794011 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -34,6 +34,8 @@
34#include <linux/slab.h> 34#include <linux/slab.h>
35#include <linux/compiler.h> 35#include <linux/compiler.h>
36#include <linux/pstore_ram.h> 36#include <linux/pstore_ram.h>
37#include <linux/of.h>
38#include <linux/of_address.h>
37 39
38#define RAMOOPS_KERNMSG_HDR "====" 40#define RAMOOPS_KERNMSG_HDR "===="
39#define MIN_MEM_SIZE 4096UL 41#define MIN_MEM_SIZE 4096UL
@@ -181,10 +183,10 @@ static bool prz_ok(struct persistent_ram_zone *prz)
181static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 183static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
182 int *count, struct timespec *time, 184 int *count, struct timespec *time,
183 char **buf, bool *compressed, 185 char **buf, bool *compressed,
186 ssize_t *ecc_notice_size,
184 struct pstore_info *psi) 187 struct pstore_info *psi)
185{ 188{
186 ssize_t size; 189 ssize_t size;
187 ssize_t ecc_notice_size;
188 struct ramoops_context *cxt = psi->data; 190 struct ramoops_context *cxt = psi->data;
189 struct persistent_ram_zone *prz = NULL; 191 struct persistent_ram_zone *prz = NULL;
190 int header_length = 0; 192 int header_length = 0;
@@ -229,16 +231,16 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
229 size = persistent_ram_old_size(prz) - header_length; 231 size = persistent_ram_old_size(prz) - header_length;
230 232
231 /* ECC correction notice */ 233 /* ECC correction notice */
232 ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0); 234 *ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
233 235
234 *buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL); 236 *buf = kmalloc(size + *ecc_notice_size + 1, GFP_KERNEL);
235 if (*buf == NULL) 237 if (*buf == NULL)
236 return -ENOMEM; 238 return -ENOMEM;
237 239
238 memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size); 240 memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size);
239 persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1); 241 persistent_ram_ecc_string(prz, *buf + size, *ecc_notice_size + 1);
240 242
241 return size + ecc_notice_size; 243 return size;
242} 244}
243 245
244static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz, 246static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz,
@@ -458,15 +460,98 @@ static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
458 return 0; 460 return 0;
459} 461}
460 462
463static int ramoops_parse_dt_size(struct platform_device *pdev,
464 const char *propname, u32 *value)
465{
466 u32 val32 = 0;
467 int ret;
468
469 ret = of_property_read_u32(pdev->dev.of_node, propname, &val32);
470 if (ret < 0 && ret != -EINVAL) {
471 dev_err(&pdev->dev, "failed to parse property %s: %d\n",
472 propname, ret);
473 return ret;
474 }
475
476 if (val32 > INT_MAX) {
477 dev_err(&pdev->dev, "%s %u > INT_MAX\n", propname, val32);
478 return -EOVERFLOW;
479 }
480
481 *value = val32;
482 return 0;
483}
484
485static int ramoops_parse_dt(struct platform_device *pdev,
486 struct ramoops_platform_data *pdata)
487{
488 struct device_node *of_node = pdev->dev.of_node;
489 struct device_node *mem_region;
490 struct resource res;
491 u32 value;
492 int ret;
493
494 dev_dbg(&pdev->dev, "using Device Tree\n");
495
496 mem_region = of_parse_phandle(of_node, "memory-region", 0);
497 if (!mem_region) {
498 dev_err(&pdev->dev, "no memory-region phandle\n");
499 return -ENODEV;
500 }
501
502 ret = of_address_to_resource(mem_region, 0, &res);
503 of_node_put(mem_region);
504 if (ret) {
505 dev_err(&pdev->dev,
506 "failed to translate memory-region to resource: %d\n",
507 ret);
508 return ret;
509 }
510
511 pdata->mem_size = resource_size(&res);
512 pdata->mem_address = res.start;
513 pdata->mem_type = of_property_read_bool(of_node, "unbuffered");
514 pdata->dump_oops = !of_property_read_bool(of_node, "no-dump-oops");
515
516#define parse_size(name, field) { \
517 ret = ramoops_parse_dt_size(pdev, name, &value); \
518 if (ret < 0) \
519 return ret; \
520 field = value; \
521 }
522
523 parse_size("record-size", pdata->record_size);
524 parse_size("console-size", pdata->console_size);
525 parse_size("ftrace-size", pdata->ftrace_size);
526 parse_size("pmsg-size", pdata->pmsg_size);
527 parse_size("ecc-size", pdata->ecc_info.ecc_size);
528
529#undef parse_size
530
531 return 0;
532}
533
461static int ramoops_probe(struct platform_device *pdev) 534static int ramoops_probe(struct platform_device *pdev)
462{ 535{
463 struct device *dev = &pdev->dev; 536 struct device *dev = &pdev->dev;
464 struct ramoops_platform_data *pdata = pdev->dev.platform_data; 537 struct ramoops_platform_data *pdata = dev->platform_data;
465 struct ramoops_context *cxt = &oops_cxt; 538 struct ramoops_context *cxt = &oops_cxt;
466 size_t dump_mem_sz; 539 size_t dump_mem_sz;
467 phys_addr_t paddr; 540 phys_addr_t paddr;
468 int err = -EINVAL; 541 int err = -EINVAL;
469 542
543 if (dev_of_node(dev) && !pdata) {
544 pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
545 if (!pdata) {
546 err = -ENOMEM;
547 goto fail_out;
548 }
549
550 err = ramoops_parse_dt(pdev, pdata);
551 if (err < 0)
552 goto fail_out;
553 }
554
470 /* Only a single ramoops area allowed at a time, so fail extra 555 /* Only a single ramoops area allowed at a time, so fail extra
471 * probes. 556 * probes.
472 */ 557 */
@@ -596,11 +681,17 @@ static int ramoops_remove(struct platform_device *pdev)
596 return 0; 681 return 0;
597} 682}
598 683
684static const struct of_device_id dt_match[] = {
685 { .compatible = "ramoops" },
686 {}
687};
688
599static struct platform_driver ramoops_driver = { 689static struct platform_driver ramoops_driver = {
600 .probe = ramoops_probe, 690 .probe = ramoops_probe,
601 .remove = ramoops_remove, 691 .remove = ramoops_remove,
602 .driver = { 692 .driver = {
603 .name = "ramoops", 693 .name = "ramoops",
694 .of_match_table = dt_match,
604 }, 695 },
605}; 696};
606 697
diff --git a/include/linux/pstore.h b/include/linux/pstore.h
index 831479f8df8f..899e95e84400 100644
--- a/include/linux/pstore.h
+++ b/include/linux/pstore.h
@@ -58,7 +58,8 @@ struct pstore_info {
58 int (*close)(struct pstore_info *psi); 58 int (*close)(struct pstore_info *psi);
59 ssize_t (*read)(u64 *id, enum pstore_type_id *type, 59 ssize_t (*read)(u64 *id, enum pstore_type_id *type,
60 int *count, struct timespec *time, char **buf, 60 int *count, struct timespec *time, char **buf,
61 bool *compressed, struct pstore_info *psi); 61 bool *compressed, ssize_t *ecc_notice_size,
62 struct pstore_info *psi);
62 int (*write)(enum pstore_type_id type, 63 int (*write)(enum pstore_type_id type,
63 enum kmsg_dump_reason reason, u64 *id, 64 enum kmsg_dump_reason reason, u64 *id,
64 unsigned int part, int count, bool compressed, 65 unsigned int part, int count, bool compressed,