diff options
Diffstat (limited to 'arch/powerpc/platforms/pseries')
-rw-r--r-- | arch/powerpc/platforms/pseries/nvram.c | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c index e54a8b7f5c64..742735acd8b6 100644 --- a/arch/powerpc/platforms/pseries/nvram.c +++ b/arch/powerpc/platforms/pseries/nvram.c | |||
@@ -29,6 +29,13 @@ | |||
29 | /* Max bytes to read/write in one go */ | 29 | /* Max bytes to read/write in one go */ |
30 | #define NVRW_CNT 0x20 | 30 | #define NVRW_CNT 0x20 |
31 | 31 | ||
32 | /* | ||
33 | * Set oops header version to distingush between old and new format header. | ||
34 | * lnx,oops-log partition max size is 4000, header version > 4000 will | ||
35 | * help in identifying new header. | ||
36 | */ | ||
37 | #define OOPS_HDR_VERSION 5000 | ||
38 | |||
32 | static unsigned int nvram_size; | 39 | static unsigned int nvram_size; |
33 | static int nvram_fetch, nvram_store; | 40 | static int nvram_fetch, nvram_store; |
34 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ | 41 | static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ |
@@ -67,6 +74,12 @@ static const char *pseries_nvram_os_partitions[] = { | |||
67 | NULL | 74 | NULL |
68 | }; | 75 | }; |
69 | 76 | ||
77 | struct oops_log_info { | ||
78 | u16 version; | ||
79 | u16 report_length; | ||
80 | u64 timestamp; | ||
81 | } __attribute__((packed)); | ||
82 | |||
70 | static void oops_to_nvram(struct kmsg_dumper *dumper, | 83 | static void oops_to_nvram(struct kmsg_dumper *dumper, |
71 | enum kmsg_dump_reason reason); | 84 | enum kmsg_dump_reason reason); |
72 | 85 | ||
@@ -83,28 +96,28 @@ static unsigned long last_unread_rtas_event; /* timestamp */ | |||
83 | 96 | ||
84 | * big_oops_buf[] holds the uncompressed text we're capturing. | 97 | * big_oops_buf[] holds the uncompressed text we're capturing. |
85 | * | 98 | * |
86 | * oops_buf[] holds the compressed text, preceded by a prefix. | 99 | * oops_buf[] holds the compressed text, preceded by a oops header. |
87 | * The prefix is just a u16 holding the length of the compressed* text. | 100 | * oops header has u16 holding the version of oops header (to differentiate |
88 | * (*Or uncompressed, if compression fails.) oops_buf[] gets written | 101 | * between old and new format header) followed by u16 holding the length of |
89 | * to NVRAM. | 102 | * the compressed* text (*Or uncompressed, if compression fails.) and u64 |
103 | * holding the timestamp. oops_buf[] gets written to NVRAM. | ||
90 | * | 104 | * |
91 | * oops_len points to the prefix. oops_data points to the compressed text. | 105 | * oops_log_info points to the header. oops_data points to the compressed text. |
92 | * | 106 | * |
93 | * +- oops_buf | 107 | * +- oops_buf |
94 | * | +- oops_data | 108 | * | +- oops_data |
95 | * v v | 109 | * v v |
96 | * +------------+-----------------------------------------------+ | 110 | * +-----------+-----------+-----------+------------------------+ |
97 | * | length | text | | 111 | * | version | length | timestamp | text | |
98 | * | (2 bytes) | (oops_data_sz bytes) | | 112 | * | (2 bytes) | (2 bytes) | (8 bytes) | (oops_data_sz bytes) | |
99 | * +------------+-----------------------------------------------+ | 113 | * +-----------+-----------+-----------+------------------------+ |
100 | * ^ | 114 | * ^ |
101 | * +- oops_len | 115 | * +- oops_log_info |
102 | * | 116 | * |
103 | * We preallocate these buffers during init to avoid kmalloc during oops/panic. | 117 | * We preallocate these buffers during init to avoid kmalloc during oops/panic. |
104 | */ | 118 | */ |
105 | static size_t big_oops_buf_sz; | 119 | static size_t big_oops_buf_sz; |
106 | static char *big_oops_buf, *oops_buf; | 120 | static char *big_oops_buf, *oops_buf; |
107 | static u16 *oops_len; | ||
108 | static char *oops_data; | 121 | static char *oops_data; |
109 | static size_t oops_data_sz; | 122 | static size_t oops_data_sz; |
110 | 123 | ||
@@ -425,9 +438,8 @@ static void __init nvram_init_oops_partition(int rtas_partition_exists) | |||
425 | oops_log_partition.name); | 438 | oops_log_partition.name); |
426 | return; | 439 | return; |
427 | } | 440 | } |
428 | oops_len = (u16*) oops_buf; | 441 | oops_data = oops_buf + sizeof(struct oops_log_info); |
429 | oops_data = oops_buf + sizeof(u16); | 442 | oops_data_sz = oops_log_partition.size - sizeof(struct oops_log_info); |
430 | oops_data_sz = oops_log_partition.size - sizeof(u16); | ||
431 | 443 | ||
432 | /* | 444 | /* |
433 | * Figure compression (preceded by elimination of each line's <n> | 445 | * Figure compression (preceded by elimination of each line's <n> |
@@ -555,6 +567,7 @@ error: | |||
555 | /* Compress the text from big_oops_buf into oops_buf. */ | 567 | /* Compress the text from big_oops_buf into oops_buf. */ |
556 | static int zip_oops(size_t text_len) | 568 | static int zip_oops(size_t text_len) |
557 | { | 569 | { |
570 | struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; | ||
558 | int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, | 571 | int zipped_len = nvram_compress(big_oops_buf, oops_data, text_len, |
559 | oops_data_sz); | 572 | oops_data_sz); |
560 | if (zipped_len < 0) { | 573 | if (zipped_len < 0) { |
@@ -562,7 +575,9 @@ static int zip_oops(size_t text_len) | |||
562 | pr_err("nvram: logging uncompressed oops/panic report\n"); | 575 | pr_err("nvram: logging uncompressed oops/panic report\n"); |
563 | return -1; | 576 | return -1; |
564 | } | 577 | } |
565 | *oops_len = (u16) zipped_len; | 578 | oops_hdr->version = OOPS_HDR_VERSION; |
579 | oops_hdr->report_length = (u16) zipped_len; | ||
580 | oops_hdr->timestamp = get_seconds(); | ||
566 | return 0; | 581 | return 0; |
567 | } | 582 | } |
568 | 583 | ||
@@ -576,6 +591,7 @@ static int zip_oops(size_t text_len) | |||
576 | static void oops_to_nvram(struct kmsg_dumper *dumper, | 591 | static void oops_to_nvram(struct kmsg_dumper *dumper, |
577 | enum kmsg_dump_reason reason) | 592 | enum kmsg_dump_reason reason) |
578 | { | 593 | { |
594 | struct oops_log_info *oops_hdr = (struct oops_log_info *)oops_buf; | ||
579 | static unsigned int oops_count = 0; | 595 | static unsigned int oops_count = 0; |
580 | static bool panicking = false; | 596 | static bool panicking = false; |
581 | static DEFINE_SPINLOCK(lock); | 597 | static DEFINE_SPINLOCK(lock); |
@@ -622,11 +638,14 @@ static void oops_to_nvram(struct kmsg_dumper *dumper, | |||
622 | kmsg_dump_get_buffer(dumper, false, | 638 | kmsg_dump_get_buffer(dumper, false, |
623 | oops_data, oops_data_sz, &text_len); | 639 | oops_data, oops_data_sz, &text_len); |
624 | err_type = ERR_TYPE_KERNEL_PANIC; | 640 | err_type = ERR_TYPE_KERNEL_PANIC; |
625 | *oops_len = (u16) text_len; | 641 | oops_hdr->version = OOPS_HDR_VERSION; |
642 | oops_hdr->report_length = (u16) text_len; | ||
643 | oops_hdr->timestamp = get_seconds(); | ||
626 | } | 644 | } |
627 | 645 | ||
628 | (void) nvram_write_os_partition(&oops_log_partition, oops_buf, | 646 | (void) nvram_write_os_partition(&oops_log_partition, oops_buf, |
629 | (int) (sizeof(*oops_len) + *oops_len), err_type, ++oops_count); | 647 | (int) (sizeof(*oops_hdr) + oops_hdr->report_length), err_type, |
648 | ++oops_count); | ||
630 | 649 | ||
631 | spin_unlock_irqrestore(&lock, flags); | 650 | spin_unlock_irqrestore(&lock, flags); |
632 | } | 651 | } |