aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/pstore/Kconfig19
-rw-r--r--fs/pstore/Makefile1
-rw-r--r--fs/pstore/ftrace.c35
-rw-r--r--fs/pstore/inode.c114
-rw-r--r--fs/pstore/internal.h45
-rw-r--r--fs/pstore/platform.c66
-rw-r--r--fs/pstore/ram.c368
-rw-r--r--fs/pstore/ram_core.c150
8 files changed, 576 insertions, 222 deletions
diff --git a/fs/pstore/Kconfig b/fs/pstore/Kconfig
index 23ade2680a4a..d39bb5cce883 100644
--- a/fs/pstore/Kconfig
+++ b/fs/pstore/Kconfig
@@ -12,6 +12,25 @@ config PSTORE
12 If you don't have a platform persistent store driver, 12 If you don't have a platform persistent store driver,
13 say N. 13 say N.
14 14
15config PSTORE_CONSOLE
16 bool "Log kernel console messages"
17 depends on PSTORE
18 help
19 When the option is enabled, pstore will log all kernel
20 messages, even if no oops or panic happened.
21
22config PSTORE_FTRACE
23 bool "Persistent function tracer"
24 depends on PSTORE
25 depends on FUNCTION_TRACER
26 help
27 With this option kernel traces function calls into a persistent
28 ram buffer that can be decoded and dumped after reboot through
29 pstore filesystem. It can be used to determine what function
30 was last called before a reset or panic.
31
32 If unsure, say N.
33
15config PSTORE_RAM 34config PSTORE_RAM
16 tristate "Log panic/oops to a RAM buffer" 35 tristate "Log panic/oops to a RAM buffer"
17 depends on PSTORE 36 depends on PSTORE
diff --git a/fs/pstore/Makefile b/fs/pstore/Makefile
index 278a44e0d4e1..4c9095c2781e 100644
--- a/fs/pstore/Makefile
+++ b/fs/pstore/Makefile
@@ -5,6 +5,7 @@
5obj-y += pstore.o 5obj-y += pstore.o
6 6
7pstore-objs += inode.o platform.o 7pstore-objs += inode.o platform.o
8obj-$(CONFIG_PSTORE_FTRACE) += ftrace.o
8 9
9ramoops-objs += ram.o ram_core.o 10ramoops-objs += ram.o ram_core.o
10obj-$(CONFIG_PSTORE_RAM) += ramoops.o 11obj-$(CONFIG_PSTORE_RAM) += ramoops.o
diff --git a/fs/pstore/ftrace.c b/fs/pstore/ftrace.c
new file mode 100644
index 000000000000..a130d484b7d3
--- /dev/null
+++ b/fs/pstore/ftrace.c
@@ -0,0 +1,35 @@
1/*
2 * Copyright 2012 Google, Inc.
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#include <linux/kernel.h>
15#include <linux/compiler.h>
16#include <linux/irqflags.h>
17#include <linux/percpu.h>
18#include <linux/smp.h>
19#include <linux/atomic.h>
20#include <asm/barrier.h>
21#include "internal.h"
22
23void notrace pstore_ftrace_call(unsigned long ip, unsigned long parent_ip)
24{
25 struct pstore_ftrace_record rec = {};
26
27 if (unlikely(oops_in_progress))
28 return;
29
30 rec.ip = ip;
31 rec.parent_ip = parent_ip;
32 pstore_ftrace_encode_cpu(&rec, raw_smp_processor_id());
33 psinfo->write_buf(PSTORE_TYPE_FTRACE, 0, NULL, 0, (void *)&rec,
34 sizeof(rec), psinfo);
35}
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index 11a2aa2a56c4..4ab572e6d277 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -27,6 +27,7 @@
27#include <linux/list.h> 27#include <linux/list.h>
28#include <linux/string.h> 28#include <linux/string.h>
29#include <linux/mount.h> 29#include <linux/mount.h>
30#include <linux/seq_file.h>
30#include <linux/ramfs.h> 31#include <linux/ramfs.h>
31#include <linux/parser.h> 32#include <linux/parser.h>
32#include <linux/sched.h> 33#include <linux/sched.h>
@@ -52,18 +53,117 @@ struct pstore_private {
52 char data[]; 53 char data[];
53}; 54};
54 55
56struct pstore_ftrace_seq_data {
57 const void *ptr;
58 size_t off;
59 size_t size;
60};
61
62#define REC_SIZE sizeof(struct pstore_ftrace_record)
63
64static void *pstore_ftrace_seq_start(struct seq_file *s, loff_t *pos)
65{
66 struct pstore_private *ps = s->private;
67 struct pstore_ftrace_seq_data *data;
68
69 data = kzalloc(sizeof(*data), GFP_KERNEL);
70 if (!data)
71 return NULL;
72
73 data->off = ps->size % REC_SIZE;
74 data->off += *pos * REC_SIZE;
75 if (data->off + REC_SIZE > ps->size) {
76 kfree(data);
77 return NULL;
78 }
79
80 return data;
81
82}
83
84static void pstore_ftrace_seq_stop(struct seq_file *s, void *v)
85{
86 kfree(v);
87}
88
89static void *pstore_ftrace_seq_next(struct seq_file *s, void *v, loff_t *pos)
90{
91 struct pstore_private *ps = s->private;
92 struct pstore_ftrace_seq_data *data = v;
93
94 data->off += REC_SIZE;
95 if (data->off + REC_SIZE > ps->size)
96 return NULL;
97
98 (*pos)++;
99 return data;
100}
101
102static int pstore_ftrace_seq_show(struct seq_file *s, void *v)
103{
104 struct pstore_private *ps = s->private;
105 struct pstore_ftrace_seq_data *data = v;
106 struct pstore_ftrace_record *rec = (void *)(ps->data + data->off);
107
108 seq_printf(s, "%d %08lx %08lx %pf <- %pF\n",
109 pstore_ftrace_decode_cpu(rec), rec->ip, rec->parent_ip,
110 (void *)rec->ip, (void *)rec->parent_ip);
111
112 return 0;
113}
114
115static const struct seq_operations pstore_ftrace_seq_ops = {
116 .start = pstore_ftrace_seq_start,
117 .next = pstore_ftrace_seq_next,
118 .stop = pstore_ftrace_seq_stop,
119 .show = pstore_ftrace_seq_show,
120};
121
55static ssize_t pstore_file_read(struct file *file, char __user *userbuf, 122static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
56 size_t count, loff_t *ppos) 123 size_t count, loff_t *ppos)
57{ 124{
58 struct pstore_private *ps = file->private_data; 125 struct seq_file *sf = file->private_data;
126 struct pstore_private *ps = sf->private;
59 127
128 if (ps->type == PSTORE_TYPE_FTRACE)
129 return seq_read(file, userbuf, count, ppos);
60 return simple_read_from_buffer(userbuf, count, ppos, ps->data, ps->size); 130 return simple_read_from_buffer(userbuf, count, ppos, ps->data, ps->size);
61} 131}
62 132
133static int pstore_file_open(struct inode *inode, struct file *file)
134{
135 struct pstore_private *ps = inode->i_private;
136 struct seq_file *sf;
137 int err;
138 const struct seq_operations *sops = NULL;
139
140 if (ps->type == PSTORE_TYPE_FTRACE)
141 sops = &pstore_ftrace_seq_ops;
142
143 err = seq_open(file, sops);
144 if (err < 0)
145 return err;
146
147 sf = file->private_data;
148 sf->private = ps;
149
150 return 0;
151}
152
153static loff_t pstore_file_llseek(struct file *file, loff_t off, int origin)
154{
155 struct seq_file *sf = file->private_data;
156
157 if (sf->op)
158 return seq_lseek(file, off, origin);
159 return default_llseek(file, off, origin);
160}
161
63static const struct file_operations pstore_file_operations = { 162static const struct file_operations pstore_file_operations = {
64 .open = simple_open, 163 .open = pstore_file_open,
65 .read = pstore_file_read, 164 .read = pstore_file_read,
66 .llseek = default_llseek, 165 .llseek = pstore_file_llseek,
166 .release = seq_release,
67}; 167};
68 168
69/* 169/*
@@ -212,6 +312,12 @@ int pstore_mkfile(enum pstore_type_id type, char *psname, u64 id,
212 case PSTORE_TYPE_DMESG: 312 case PSTORE_TYPE_DMESG:
213 sprintf(name, "dmesg-%s-%lld", psname, id); 313 sprintf(name, "dmesg-%s-%lld", psname, id);
214 break; 314 break;
315 case PSTORE_TYPE_CONSOLE:
316 sprintf(name, "console-%s", psname);
317 break;
318 case PSTORE_TYPE_FTRACE:
319 sprintf(name, "ftrace-%s", psname);
320 break;
215 case PSTORE_TYPE_MCE: 321 case PSTORE_TYPE_MCE:
216 sprintf(name, "mce-%s-%lld", psname, id); 322 sprintf(name, "mce-%s-%lld", psname, id);
217 break; 323 break;
diff --git a/fs/pstore/internal.h b/fs/pstore/internal.h
index 3bde461c3f34..0d0d3b7d5f12 100644
--- a/fs/pstore/internal.h
+++ b/fs/pstore/internal.h
@@ -1,6 +1,51 @@
1#ifndef __PSTORE_INTERNAL_H__
2#define __PSTORE_INTERNAL_H__
3
4#include <linux/types.h>
5#include <linux/time.h>
6#include <linux/pstore.h>
7
8#if NR_CPUS <= 2 && defined(CONFIG_ARM_THUMB)
9#define PSTORE_CPU_IN_IP 0x1
10#elif NR_CPUS <= 4 && defined(CONFIG_ARM)
11#define PSTORE_CPU_IN_IP 0x3
12#endif
13
14struct pstore_ftrace_record {
15 unsigned long ip;
16 unsigned long parent_ip;
17#ifndef PSTORE_CPU_IN_IP
18 unsigned int cpu;
19#endif
20};
21
22static inline void
23pstore_ftrace_encode_cpu(struct pstore_ftrace_record *rec, unsigned int cpu)
24{
25#ifndef PSTORE_CPU_IN_IP
26 rec->cpu = cpu;
27#else
28 rec->ip |= cpu;
29#endif
30}
31
32static inline unsigned int
33pstore_ftrace_decode_cpu(struct pstore_ftrace_record *rec)
34{
35#ifndef PSTORE_CPU_IN_IP
36 return rec->cpu;
37#else
38 return rec->ip & PSTORE_CPU_IN_IP;
39#endif
40}
41
42extern struct pstore_info *psinfo;
43
1extern void pstore_set_kmsg_bytes(int); 44extern void pstore_set_kmsg_bytes(int);
2extern void pstore_get_records(int); 45extern void pstore_get_records(int);
3extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id, 46extern int pstore_mkfile(enum pstore_type_id, char *psname, u64 id,
4 char *data, size_t size, 47 char *data, size_t size,
5 struct timespec time, struct pstore_info *psi); 48 struct timespec time, struct pstore_info *psi);
6extern int pstore_is_mounted(void); 49extern int pstore_is_mounted(void);
50
51#endif
diff --git a/fs/pstore/platform.c b/fs/pstore/platform.c
index 03ce7a9b81cc..29996e8793a7 100644
--- a/fs/pstore/platform.c
+++ b/fs/pstore/platform.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * Persistent Storage - platform driver interface parts. 2 * Persistent Storage - platform driver interface parts.
3 * 3 *
4 * Copyright (C) 2007-2008 Google, Inc.
4 * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com> 5 * Copyright (C) 2010 Intel Corporation <tony.luck@intel.com>
5 * 6 *
6 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
22#include <linux/errno.h> 23#include <linux/errno.h>
23#include <linux/init.h> 24#include <linux/init.h>
24#include <linux/kmsg_dump.h> 25#include <linux/kmsg_dump.h>
26#include <linux/console.h>
25#include <linux/module.h> 27#include <linux/module.h>
26#include <linux/pstore.h> 28#include <linux/pstore.h>
27#include <linux/string.h> 29#include <linux/string.h>
@@ -29,6 +31,7 @@
29#include <linux/slab.h> 31#include <linux/slab.h>
30#include <linux/uaccess.h> 32#include <linux/uaccess.h>
31#include <linux/hardirq.h> 33#include <linux/hardirq.h>
34#include <linux/jiffies.h>
32#include <linux/workqueue.h> 35#include <linux/workqueue.h>
33 36
34#include "internal.h" 37#include "internal.h"
@@ -38,7 +41,12 @@
38 * whether the system is actually still running well enough 41 * whether the system is actually still running well enough
39 * to let someone see the entry 42 * to let someone see the entry
40 */ 43 */
41#define PSTORE_INTERVAL (60 * HZ) 44static int pstore_update_ms = -1;
45module_param_named(update_ms, pstore_update_ms, int, 0600);
46MODULE_PARM_DESC(update_ms, "milliseconds before pstore updates its content "
47 "(default is -1, which means runtime updates are disabled; "
48 "enabling this option is not safe, it may lead to further "
49 "corruption on Oopses)");
42 50
43static int pstore_new_entry; 51static int pstore_new_entry;
44 52
@@ -53,7 +61,7 @@ static DECLARE_WORK(pstore_work, pstore_dowork);
53 * calls to pstore_register() 61 * calls to pstore_register()
54 */ 62 */
55static DEFINE_SPINLOCK(pstore_lock); 63static DEFINE_SPINLOCK(pstore_lock);
56static struct pstore_info *psinfo; 64struct pstore_info *psinfo;
57 65
58static char *backend; 66static char *backend;
59 67
@@ -146,6 +154,48 @@ static struct kmsg_dumper pstore_dumper = {
146 .dump = pstore_dump, 154 .dump = pstore_dump,
147}; 155};
148 156
157#ifdef CONFIG_PSTORE_CONSOLE
158static void pstore_console_write(struct console *con, const char *s, unsigned c)
159{
160 const char *e = s + c;
161
162 while (s < e) {
163 unsigned long flags;
164
165 if (c > psinfo->bufsize)
166 c = psinfo->bufsize;
167 spin_lock_irqsave(&psinfo->buf_lock, flags);
168 memcpy(psinfo->buf, s, c);
169 psinfo->write(PSTORE_TYPE_CONSOLE, 0, NULL, 0, c, psinfo);
170 spin_unlock_irqrestore(&psinfo->buf_lock, flags);
171 s += c;
172 c = e - s;
173 }
174}
175
176static struct console pstore_console = {
177 .name = "pstore",
178 .write = pstore_console_write,
179 .flags = CON_PRINTBUFFER | CON_ENABLED | CON_ANYTIME,
180 .index = -1,
181};
182
183static void pstore_register_console(void)
184{
185 register_console(&pstore_console);
186}
187#else
188static void pstore_register_console(void) {}
189#endif
190
191static int pstore_write_compat(enum pstore_type_id type,
192 enum kmsg_dump_reason reason,
193 u64 *id, unsigned int part,
194 size_t size, struct pstore_info *psi)
195{
196 return psi->write_buf(type, reason, id, part, psinfo->buf, size, psi);
197}
198
149/* 199/*
150 * platform specific persistent storage driver registers with 200 * platform specific persistent storage driver registers with
151 * us here. If pstore is already mounted, call the platform 201 * us here. If pstore is already mounted, call the platform
@@ -170,6 +220,8 @@ int pstore_register(struct pstore_info *psi)
170 return -EINVAL; 220 return -EINVAL;
171 } 221 }
172 222
223 if (!psi->write)
224 psi->write = pstore_write_compat;
173 psinfo = psi; 225 psinfo = psi;
174 mutex_init(&psinfo->read_mutex); 226 mutex_init(&psinfo->read_mutex);
175 spin_unlock(&pstore_lock); 227 spin_unlock(&pstore_lock);
@@ -183,9 +235,13 @@ int pstore_register(struct pstore_info *psi)
183 pstore_get_records(0); 235 pstore_get_records(0);
184 236
185 kmsg_dump_register(&pstore_dumper); 237 kmsg_dump_register(&pstore_dumper);
238 pstore_register_console();
186 239
187 pstore_timer.expires = jiffies + PSTORE_INTERVAL; 240 if (pstore_update_ms >= 0) {
188 add_timer(&pstore_timer); 241 pstore_timer.expires = jiffies +
242 msecs_to_jiffies(pstore_update_ms);
243 add_timer(&pstore_timer);
244 }
189 245
190 return 0; 246 return 0;
191} 247}
@@ -244,7 +300,7 @@ static void pstore_timefunc(unsigned long dummy)
244 schedule_work(&pstore_work); 300 schedule_work(&pstore_work);
245 } 301 }
246 302
247 mod_timer(&pstore_timer, jiffies + PSTORE_INTERVAL); 303 mod_timer(&pstore_timer, jiffies + msecs_to_jiffies(pstore_update_ms));
248} 304}
249 305
250module_param(backend, charp, 0444); 306module_param(backend, charp, 0444);
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 453030f9c5bc..0b311bc18916 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -25,6 +25,7 @@
25#include <linux/kernel.h> 25#include <linux/kernel.h>
26#include <linux/err.h> 26#include <linux/err.h>
27#include <linux/module.h> 27#include <linux/module.h>
28#include <linux/version.h>
28#include <linux/pstore.h> 29#include <linux/pstore.h>
29#include <linux/time.h> 30#include <linux/time.h>
30#include <linux/io.h> 31#include <linux/io.h>
@@ -41,6 +42,14 @@ module_param(record_size, ulong, 0400);
41MODULE_PARM_DESC(record_size, 42MODULE_PARM_DESC(record_size,
42 "size of each dump done on oops/panic"); 43 "size of each dump done on oops/panic");
43 44
45static ulong ramoops_console_size = MIN_MEM_SIZE;
46module_param_named(console_size, ramoops_console_size, ulong, 0400);
47MODULE_PARM_DESC(console_size, "size of kernel console log");
48
49static ulong ramoops_ftrace_size = MIN_MEM_SIZE;
50module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400);
51MODULE_PARM_DESC(ftrace_size, "size of ftrace log");
52
44static ulong mem_address; 53static ulong mem_address;
45module_param(mem_address, ulong, 0400); 54module_param(mem_address, ulong, 0400);
46MODULE_PARM_DESC(mem_address, 55MODULE_PARM_DESC(mem_address,
@@ -59,18 +68,26 @@ MODULE_PARM_DESC(dump_oops,
59static int ramoops_ecc; 68static int ramoops_ecc;
60module_param_named(ecc, ramoops_ecc, int, 0600); 69module_param_named(ecc, ramoops_ecc, int, 0600);
61MODULE_PARM_DESC(ramoops_ecc, 70MODULE_PARM_DESC(ramoops_ecc,
62 "set to 1 to enable ECC support"); 71 "if non-zero, the option enables ECC support and specifies "
72 "ECC buffer size in bytes (1 is a special value, means 16 "
73 "bytes ECC)");
63 74
64struct ramoops_context { 75struct ramoops_context {
65 struct persistent_ram_zone **przs; 76 struct persistent_ram_zone **przs;
77 struct persistent_ram_zone *cprz;
78 struct persistent_ram_zone *fprz;
66 phys_addr_t phys_addr; 79 phys_addr_t phys_addr;
67 unsigned long size; 80 unsigned long size;
68 size_t record_size; 81 size_t record_size;
82 size_t console_size;
83 size_t ftrace_size;
69 int dump_oops; 84 int dump_oops;
70 bool ecc; 85 int ecc_size;
71 unsigned int count; 86 unsigned int max_dump_cnt;
72 unsigned int max_count; 87 unsigned int dump_write_cnt;
73 unsigned int read_count; 88 unsigned int dump_read_cnt;
89 unsigned int console_read_cnt;
90 unsigned int ftrace_read_cnt;
74 struct pstore_info pstore; 91 struct pstore_info pstore;
75}; 92};
76 93
@@ -81,10 +98,38 @@ static int ramoops_pstore_open(struct pstore_info *psi)
81{ 98{
82 struct ramoops_context *cxt = psi->data; 99 struct ramoops_context *cxt = psi->data;
83 100
84 cxt->read_count = 0; 101 cxt->dump_read_cnt = 0;
102 cxt->console_read_cnt = 0;
85 return 0; 103 return 0;
86} 104}
87 105
106static struct persistent_ram_zone *
107ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
108 u64 *id,
109 enum pstore_type_id *typep, enum pstore_type_id type,
110 bool update)
111{
112 struct persistent_ram_zone *prz;
113 int i = (*c)++;
114
115 if (i >= max)
116 return NULL;
117
118 prz = przs[i];
119
120 if (update) {
121 /* Update old/shadowed buffer. */
122 persistent_ram_save_old(prz);
123 if (!persistent_ram_old_size(prz))
124 return NULL;
125 }
126
127 *typep = type;
128 *id = i;
129
130 return prz;
131}
132
88static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 133static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
89 struct timespec *time, 134 struct timespec *time,
90 char **buf, 135 char **buf,
@@ -94,20 +139,22 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
94 struct ramoops_context *cxt = psi->data; 139 struct ramoops_context *cxt = psi->data;
95 struct persistent_ram_zone *prz; 140 struct persistent_ram_zone *prz;
96 141
97 if (cxt->read_count >= cxt->max_count) 142 prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
98 return -EINVAL; 143 cxt->max_dump_cnt, id, type,
144 PSTORE_TYPE_DMESG, 1);
145 if (!prz)
146 prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
147 1, id, type, PSTORE_TYPE_CONSOLE, 0);
148 if (!prz)
149 prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
150 1, id, type, PSTORE_TYPE_FTRACE, 0);
151 if (!prz)
152 return 0;
99 153
100 *id = cxt->read_count++;
101 prz = cxt->przs[*id];
102
103 /* Only supports dmesg output so far. */
104 *type = PSTORE_TYPE_DMESG;
105 /* TODO(kees): Bogus time for the moment. */ 154 /* TODO(kees): Bogus time for the moment. */
106 time->tv_sec = 0; 155 time->tv_sec = 0;
107 time->tv_nsec = 0; 156 time->tv_nsec = 0;
108 157
109 /* Update old/shadowed buffer. */
110 persistent_ram_save_old(prz);
111 size = persistent_ram_old_size(prz); 158 size = persistent_ram_old_size(prz);
112 *buf = kmalloc(size, GFP_KERNEL); 159 *buf = kmalloc(size, GFP_KERNEL);
113 if (*buf == NULL) 160 if (*buf == NULL)
@@ -134,17 +181,29 @@ static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
134 return len; 181 return len;
135} 182}
136 183
137static int ramoops_pstore_write(enum pstore_type_id type, 184
138 enum kmsg_dump_reason reason, 185static int ramoops_pstore_write_buf(enum pstore_type_id type,
139 u64 *id, 186 enum kmsg_dump_reason reason,
140 unsigned int part, 187 u64 *id, unsigned int part,
141 size_t size, struct pstore_info *psi) 188 const char *buf, size_t size,
189 struct pstore_info *psi)
142{ 190{
143 struct ramoops_context *cxt = psi->data; 191 struct ramoops_context *cxt = psi->data;
144 struct persistent_ram_zone *prz = cxt->przs[cxt->count]; 192 struct persistent_ram_zone *prz = cxt->przs[cxt->dump_write_cnt];
145 size_t hlen; 193 size_t hlen;
146 194
147 /* Currently ramoops is designed to only store dmesg dumps. */ 195 if (type == PSTORE_TYPE_CONSOLE) {
196 if (!cxt->cprz)
197 return -ENOMEM;
198 persistent_ram_write(cxt->cprz, buf, size);
199 return 0;
200 } else if (type == PSTORE_TYPE_FTRACE) {
201 if (!cxt->fprz)
202 return -ENOMEM;
203 persistent_ram_write(cxt->fprz, buf, size);
204 return 0;
205 }
206
148 if (type != PSTORE_TYPE_DMESG) 207 if (type != PSTORE_TYPE_DMESG)
149 return -EINVAL; 208 return -EINVAL;
150 209
@@ -170,9 +229,9 @@ static int ramoops_pstore_write(enum pstore_type_id type,
170 hlen = ramoops_write_kmsg_hdr(prz); 229 hlen = ramoops_write_kmsg_hdr(prz);
171 if (size + hlen > prz->buffer_size) 230 if (size + hlen > prz->buffer_size)
172 size = prz->buffer_size - hlen; 231 size = prz->buffer_size - hlen;
173 persistent_ram_write(prz, cxt->pstore.buf, size); 232 persistent_ram_write(prz, buf, size);
174 233
175 cxt->count = (cxt->count + 1) % cxt->max_count; 234 cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt;
176 235
177 return 0; 236 return 0;
178} 237}
@@ -181,12 +240,26 @@ static int ramoops_pstore_erase(enum pstore_type_id type, u64 id,
181 struct pstore_info *psi) 240 struct pstore_info *psi)
182{ 241{
183 struct ramoops_context *cxt = psi->data; 242 struct ramoops_context *cxt = psi->data;
243 struct persistent_ram_zone *prz;
184 244
185 if (id >= cxt->max_count) 245 switch (type) {
246 case PSTORE_TYPE_DMESG:
247 if (id >= cxt->max_dump_cnt)
248 return -EINVAL;
249 prz = cxt->przs[id];
250 break;
251 case PSTORE_TYPE_CONSOLE:
252 prz = cxt->cprz;
253 break;
254 case PSTORE_TYPE_FTRACE:
255 prz = cxt->fprz;
256 break;
257 default:
186 return -EINVAL; 258 return -EINVAL;
259 }
187 260
188 persistent_ram_free_old(cxt->przs[id]); 261 persistent_ram_free_old(prz);
189 persistent_ram_zap(cxt->przs[id]); 262 persistent_ram_zap(prz);
190 263
191 return 0; 264 return 0;
192} 265}
@@ -197,78 +270,157 @@ static struct ramoops_context oops_cxt = {
197 .name = "ramoops", 270 .name = "ramoops",
198 .open = ramoops_pstore_open, 271 .open = ramoops_pstore_open,
199 .read = ramoops_pstore_read, 272 .read = ramoops_pstore_read,
200 .write = ramoops_pstore_write, 273 .write_buf = ramoops_pstore_write_buf,
201 .erase = ramoops_pstore_erase, 274 .erase = ramoops_pstore_erase,
202 }, 275 },
203}; 276};
204 277
205static int __init ramoops_probe(struct platform_device *pdev) 278static void ramoops_free_przs(struct ramoops_context *cxt)
279{
280 int i;
281
282 if (!cxt->przs)
283 return;
284
285 for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
286 persistent_ram_free(cxt->przs[i]);
287 kfree(cxt->przs);
288}
289
290static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
291 phys_addr_t *paddr, size_t dump_mem_sz)
292{
293 int err = -ENOMEM;
294 int i;
295
296 if (!cxt->record_size)
297 return 0;
298
299 cxt->max_dump_cnt = dump_mem_sz / cxt->record_size;
300 if (!cxt->max_dump_cnt)
301 return -ENOMEM;
302
303 cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
304 GFP_KERNEL);
305 if (!cxt->przs) {
306 dev_err(dev, "failed to initialize a prz array for dumps\n");
307 return -ENOMEM;
308 }
309
310 for (i = 0; i < cxt->max_dump_cnt; i++) {
311 size_t sz = cxt->record_size;
312
313 cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, cxt->ecc_size);
314 if (IS_ERR(cxt->przs[i])) {
315 err = PTR_ERR(cxt->przs[i]);
316 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
317 sz, (unsigned long long)*paddr, err);
318 goto fail_prz;
319 }
320 *paddr += sz;
321 }
322
323 return 0;
324fail_prz:
325 ramoops_free_przs(cxt);
326 return err;
327}
328
329static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
330 struct persistent_ram_zone **prz,
331 phys_addr_t *paddr, size_t sz, u32 sig)
332{
333 if (!sz)
334 return 0;
335
336 if (*paddr + sz > *paddr + cxt->size)
337 return -ENOMEM;
338
339 *prz = persistent_ram_new(*paddr, sz, sig, cxt->ecc_size);
340 if (IS_ERR(*prz)) {
341 int err = PTR_ERR(*prz);
342
343 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
344 sz, (unsigned long long)*paddr, err);
345 return err;
346 }
347
348 persistent_ram_zap(*prz);
349
350 *paddr += sz;
351
352 return 0;
353}
354
355static int __devinit ramoops_probe(struct platform_device *pdev)
206{ 356{
207 struct device *dev = &pdev->dev; 357 struct device *dev = &pdev->dev;
208 struct ramoops_platform_data *pdata = pdev->dev.platform_data; 358 struct ramoops_platform_data *pdata = pdev->dev.platform_data;
209 struct ramoops_context *cxt = &oops_cxt; 359 struct ramoops_context *cxt = &oops_cxt;
360 size_t dump_mem_sz;
361 phys_addr_t paddr;
210 int err = -EINVAL; 362 int err = -EINVAL;
211 int i;
212 363
213 /* Only a single ramoops area allowed at a time, so fail extra 364 /* Only a single ramoops area allowed at a time, so fail extra
214 * probes. 365 * probes.
215 */ 366 */
216 if (cxt->max_count) 367 if (cxt->max_dump_cnt)
217 goto fail_out; 368 goto fail_out;
218 369
219 if (!pdata->mem_size || !pdata->record_size) { 370 if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
220 pr_err("The memory size and the record size must be " 371 !pdata->ftrace_size)) {
372 pr_err("The memory size and the record/console size must be "
221 "non-zero\n"); 373 "non-zero\n");
222 goto fail_out; 374 goto fail_out;
223 } 375 }
224 376
225 pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); 377 pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
226 pdata->record_size = rounddown_pow_of_two(pdata->record_size); 378 pdata->record_size = rounddown_pow_of_two(pdata->record_size);
379 pdata->console_size = rounddown_pow_of_two(pdata->console_size);
380 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
227 381
228 /* Check for the minimum memory size */ 382 cxt->dump_read_cnt = 0;
229 if (pdata->mem_size < MIN_MEM_SIZE &&
230 pdata->record_size < MIN_MEM_SIZE) {
231 pr_err("memory size too small, minimum is %lu\n",
232 MIN_MEM_SIZE);
233 goto fail_out;
234 }
235
236 if (pdata->mem_size < pdata->record_size) {
237 pr_err("The memory size must be larger than the "
238 "records size\n");
239 goto fail_out;
240 }
241
242 cxt->max_count = pdata->mem_size / pdata->record_size;
243 cxt->count = 0;
244 cxt->size = pdata->mem_size; 383 cxt->size = pdata->mem_size;
245 cxt->phys_addr = pdata->mem_address; 384 cxt->phys_addr = pdata->mem_address;
246 cxt->record_size = pdata->record_size; 385 cxt->record_size = pdata->record_size;
386 cxt->console_size = pdata->console_size;
387 cxt->ftrace_size = pdata->ftrace_size;
247 cxt->dump_oops = pdata->dump_oops; 388 cxt->dump_oops = pdata->dump_oops;
248 cxt->ecc = pdata->ecc; 389 cxt->ecc_size = pdata->ecc_size;
249 390
250 cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_count, GFP_KERNEL); 391 paddr = cxt->phys_addr;
251 if (!cxt->przs) { 392
252 err = -ENOMEM; 393 dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size;
253 dev_err(dev, "failed to initialize a prz array\n"); 394 err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
395 if (err)
254 goto fail_out; 396 goto fail_out;
255 }
256 397
257 for (i = 0; i < cxt->max_count; i++) { 398 err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr,
258 size_t sz = cxt->record_size; 399 cxt->console_size, 0);
259 phys_addr_t start = cxt->phys_addr + sz * i; 400 if (err)
401 goto fail_init_cprz;
260 402
261 cxt->przs[i] = persistent_ram_new(start, sz, cxt->ecc); 403 err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size,
262 if (IS_ERR(cxt->przs[i])) { 404 LINUX_VERSION_CODE);
263 err = PTR_ERR(cxt->przs[i]); 405 if (err)
264 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", 406 goto fail_init_fprz;
265 sz, (unsigned long long)start, err); 407
266 goto fail_przs; 408 if (!cxt->przs && !cxt->cprz && !cxt->fprz) {
267 } 409 pr_err("memory size too small, minimum is %lu\n",
410 cxt->console_size + cxt->record_size +
411 cxt->ftrace_size);
412 goto fail_cnt;
268 } 413 }
269 414
270 cxt->pstore.data = cxt; 415 cxt->pstore.data = cxt;
271 cxt->pstore.bufsize = cxt->przs[0]->buffer_size; 416 /*
417 * Console can handle any buffer size, so prefer dumps buffer
418 * size since usually it is smaller.
419 */
420 if (cxt->przs)
421 cxt->pstore.bufsize = cxt->przs[0]->buffer_size;
422 else
423 cxt->pstore.bufsize = cxt->cprz->buffer_size;
272 cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); 424 cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
273 spin_lock_init(&cxt->pstore.buf_lock); 425 spin_lock_init(&cxt->pstore.buf_lock);
274 if (!cxt->pstore.buf) { 426 if (!cxt->pstore.buf) {
@@ -291,10 +443,9 @@ static int __init ramoops_probe(struct platform_device *pdev)
291 record_size = pdata->record_size; 443 record_size = pdata->record_size;
292 dump_oops = pdata->dump_oops; 444 dump_oops = pdata->dump_oops;
293 445
294 pr_info("attached 0x%lx@0x%llx (%ux0x%zx), ecc: %s\n", 446 pr_info("attached 0x%lx@0x%llx, ecc: %d\n",
295 cxt->size, (unsigned long long)cxt->phys_addr, 447 cxt->size, (unsigned long long)cxt->phys_addr,
296 cxt->max_count, cxt->record_size, 448 cxt->ecc_size);
297 ramoops_ecc ? "on" : "off");
298 449
299 return 0; 450 return 0;
300 451
@@ -302,11 +453,13 @@ fail_buf:
302 kfree(cxt->pstore.buf); 453 kfree(cxt->pstore.buf);
303fail_clear: 454fail_clear:
304 cxt->pstore.bufsize = 0; 455 cxt->pstore.bufsize = 0;
305 cxt->max_count = 0; 456 cxt->max_dump_cnt = 0;
306fail_przs: 457fail_cnt:
307 for (i = 0; cxt->przs[i]; i++) 458 kfree(cxt->fprz);
308 persistent_ram_free(cxt->przs[i]); 459fail_init_fprz:
309 kfree(cxt->przs); 460 kfree(cxt->cprz);
461fail_init_cprz:
462 ramoops_free_przs(cxt);
310fail_out: 463fail_out:
311 return err; 464 return err;
312} 465}
@@ -321,7 +474,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
321 474
322 iounmap(cxt->virt_addr); 475 iounmap(cxt->virt_addr);
323 release_mem_region(cxt->phys_addr, cxt->size); 476 release_mem_region(cxt->phys_addr, cxt->size);
324 cxt->max_count = 0; 477 cxt->max_dump_cnt = 0;
325 478
326 /* TODO(kees): When pstore supports unregistering, call it here. */ 479 /* TODO(kees): When pstore supports unregistering, call it here. */
327 kfree(cxt->pstore.buf); 480 kfree(cxt->pstore.buf);
@@ -333,6 +486,7 @@ static int __exit ramoops_remove(struct platform_device *pdev)
333} 486}
334 487
335static struct platform_driver ramoops_driver = { 488static struct platform_driver ramoops_driver = {
489 .probe = ramoops_probe,
336 .remove = __exit_p(ramoops_remove), 490 .remove = __exit_p(ramoops_remove),
337 .driver = { 491 .driver = {
338 .name = "ramoops", 492 .name = "ramoops",
@@ -340,45 +494,51 @@ static struct platform_driver ramoops_driver = {
340 }, 494 },
341}; 495};
342 496
343static int __init ramoops_init(void) 497static void ramoops_register_dummy(void)
344{ 498{
345 int ret; 499 if (!mem_size)
346 ret = platform_driver_probe(&ramoops_driver, ramoops_probe); 500 return;
347 if (ret == -ENODEV) { 501
348 /* 502 pr_info("using module parameters\n");
349 * If we didn't find a platform device, we use module parameters 503
350 * building platform data on the fly. 504 dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL);
351 */ 505 if (!dummy_data) {
352 pr_info("platform device not found, using module parameters\n"); 506 pr_info("could not allocate pdata\n");
353 dummy_data = kzalloc(sizeof(struct ramoops_platform_data), 507 return;
354 GFP_KERNEL); 508 }
355 if (!dummy_data) 509
356 return -ENOMEM; 510 dummy_data->mem_size = mem_size;
357 dummy_data->mem_size = mem_size; 511 dummy_data->mem_address = mem_address;
358 dummy_data->mem_address = mem_address; 512 dummy_data->record_size = record_size;
359 dummy_data->record_size = record_size; 513 dummy_data->console_size = ramoops_console_size;
360 dummy_data->dump_oops = dump_oops; 514 dummy_data->ftrace_size = ramoops_ftrace_size;
361 dummy_data->ecc = ramoops_ecc; 515 dummy_data->dump_oops = dump_oops;
362 dummy = platform_create_bundle(&ramoops_driver, ramoops_probe, 516 /*
363 NULL, 0, dummy_data, 517 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
364 sizeof(struct ramoops_platform_data)); 518 * (using 1 byte for ECC isn't much of use anyway).
365 519 */
366 if (IS_ERR(dummy)) 520 dummy_data->ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc;
367 ret = PTR_ERR(dummy); 521
368 else 522 dummy = platform_device_register_data(NULL, "ramoops", -1,
369 ret = 0; 523 dummy_data, sizeof(struct ramoops_platform_data));
524 if (IS_ERR(dummy)) {
525 pr_info("could not create platform device: %ld\n",
526 PTR_ERR(dummy));
370 } 527 }
528}
371 529
372 return ret; 530static int __init ramoops_init(void)
531{
532 ramoops_register_dummy();
533 return platform_driver_register(&ramoops_driver);
373} 534}
535postcore_initcall(ramoops_init);
374 536
375static void __exit ramoops_exit(void) 537static void __exit ramoops_exit(void)
376{ 538{
377 platform_driver_unregister(&ramoops_driver); 539 platform_driver_unregister(&ramoops_driver);
378 kfree(dummy_data); 540 kfree(dummy_data);
379} 541}
380
381module_init(ramoops_init);
382module_exit(ramoops_exit); 542module_exit(ramoops_exit);
383 543
384MODULE_LICENSE("GPL"); 544MODULE_LICENSE("GPL");
diff --git a/fs/pstore/ram_core.c b/fs/pstore/ram_core.c
index c5fbdbbf81ac..eecd2a8a84dd 100644
--- a/fs/pstore/ram_core.c
+++ b/fs/pstore/ram_core.c
@@ -35,8 +35,6 @@ struct persistent_ram_buffer {
35 35
36#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ 36#define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
37 37
38static __initdata LIST_HEAD(persistent_ram_list);
39
40static inline size_t buffer_size(struct persistent_ram_zone *prz) 38static inline size_t buffer_size(struct persistent_ram_zone *prz)
41{ 39{
42 return atomic_read(&prz->buffer->size); 40 return atomic_read(&prz->buffer->size);
@@ -116,7 +114,7 @@ static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
116 int ecc_size = prz->ecc_size; 114 int ecc_size = prz->ecc_size;
117 int size = prz->ecc_block_size; 115 int size = prz->ecc_block_size;
118 116
119 if (!prz->ecc) 117 if (!prz->ecc_size)
120 return; 118 return;
121 119
122 block = buffer->data + (start & ~(ecc_block_size - 1)); 120 block = buffer->data + (start & ~(ecc_block_size - 1));
@@ -135,7 +133,7 @@ static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
135{ 133{
136 struct persistent_ram_buffer *buffer = prz->buffer; 134 struct persistent_ram_buffer *buffer = prz->buffer;
137 135
138 if (!prz->ecc) 136 if (!prz->ecc_size)
139 return; 137 return;
140 138
141 persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer), 139 persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
@@ -148,7 +146,7 @@ static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
148 uint8_t *block; 146 uint8_t *block;
149 uint8_t *par; 147 uint8_t *par;
150 148
151 if (!prz->ecc) 149 if (!prz->ecc_size)
152 return; 150 return;
153 151
154 block = buffer->data; 152 block = buffer->data;
@@ -174,29 +172,30 @@ static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
174} 172}
175 173
176static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, 174static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
177 size_t buffer_size) 175 int ecc_size)
178{ 176{
179 int numerr; 177 int numerr;
180 struct persistent_ram_buffer *buffer = prz->buffer; 178 struct persistent_ram_buffer *buffer = prz->buffer;
181 int ecc_blocks; 179 int ecc_blocks;
180 size_t ecc_total;
181 int ecc_symsize = 8;
182 int ecc_poly = 0x11d;
182 183
183 if (!prz->ecc) 184 if (!ecc_size)
184 return 0; 185 return 0;
185 186
186 prz->ecc_block_size = 128; 187 prz->ecc_block_size = 128;
187 prz->ecc_size = 16; 188 prz->ecc_size = ecc_size;
188 prz->ecc_symsize = 8;
189 prz->ecc_poly = 0x11d;
190 189
191 ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size); 190 ecc_blocks = DIV_ROUND_UP(prz->buffer_size, prz->ecc_block_size);
192 prz->buffer_size -= (ecc_blocks + 1) * prz->ecc_size; 191 ecc_total = (ecc_blocks + 1) * prz->ecc_size;
193 192 if (ecc_total >= prz->buffer_size) {
194 if (prz->buffer_size > buffer_size) { 193 pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
195 pr_err("persistent_ram: invalid size %zu, non-ecc datasize %zu\n", 194 __func__, prz->ecc_size, ecc_total, prz->buffer_size);
196 buffer_size, prz->buffer_size);
197 return -EINVAL; 195 return -EINVAL;
198 } 196 }
199 197
198 prz->buffer_size -= ecc_total;
200 prz->par_buffer = buffer->data + prz->buffer_size; 199 prz->par_buffer = buffer->data + prz->buffer_size;
201 prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size; 200 prz->par_header = prz->par_buffer + ecc_blocks * prz->ecc_size;
202 201
@@ -204,8 +203,7 @@ static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
204 * first consecutive root is 0 203 * first consecutive root is 0
205 * primitive element to generate roots = 1 204 * primitive element to generate roots = 1
206 */ 205 */
207 prz->rs_decoder = init_rs(prz->ecc_symsize, prz->ecc_poly, 0, 1, 206 prz->rs_decoder = init_rs(ecc_symsize, ecc_poly, 0, 1, prz->ecc_size);
208 prz->ecc_size);
209 if (prz->rs_decoder == NULL) { 207 if (prz->rs_decoder == NULL) {
210 pr_info("persistent_ram: init_rs failed\n"); 208 pr_info("persistent_ram: init_rs failed\n");
211 return -EINVAL; 209 return -EINVAL;
@@ -392,35 +390,36 @@ static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
392 return 0; 390 return 0;
393} 391}
394 392
395static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool ecc) 393static int __devinit persistent_ram_post_init(struct persistent_ram_zone *prz,
394 u32 sig, int ecc_size)
396{ 395{
397 int ret; 396 int ret;
398 397
399 prz->ecc = ecc; 398 ret = persistent_ram_init_ecc(prz, ecc_size);
400
401 ret = persistent_ram_init_ecc(prz, prz->buffer_size);
402 if (ret) 399 if (ret)
403 return ret; 400 return ret;
404 401
405 if (prz->buffer->sig == PERSISTENT_RAM_SIG) { 402 sig ^= PERSISTENT_RAM_SIG;
403
404 if (prz->buffer->sig == sig) {
406 if (buffer_size(prz) > prz->buffer_size || 405 if (buffer_size(prz) > prz->buffer_size ||
407 buffer_start(prz) > buffer_size(prz)) 406 buffer_start(prz) > buffer_size(prz))
408 pr_info("persistent_ram: found existing invalid buffer," 407 pr_info("persistent_ram: found existing invalid buffer,"
409 " size %zu, start %zu\n", 408 " size %zu, start %zu\n",
410 buffer_size(prz), buffer_start(prz)); 409 buffer_size(prz), buffer_start(prz));
411 else { 410 else {
412 pr_info("persistent_ram: found existing buffer," 411 pr_debug("persistent_ram: found existing buffer,"
413 " size %zu, start %zu\n", 412 " size %zu, start %zu\n",
414 buffer_size(prz), buffer_start(prz)); 413 buffer_size(prz), buffer_start(prz));
415 persistent_ram_save_old(prz); 414 persistent_ram_save_old(prz);
416 return 0; 415 return 0;
417 } 416 }
418 } else { 417 } else {
419 pr_info("persistent_ram: no valid data in buffer" 418 pr_debug("persistent_ram: no valid data in buffer"
420 " (sig = 0x%08x)\n", prz->buffer->sig); 419 " (sig = 0x%08x)\n", prz->buffer->sig);
421 } 420 }
422 421
423 prz->buffer->sig = PERSISTENT_RAM_SIG; 422 prz->buffer->sig = sig;
424 persistent_ram_zap(prz); 423 persistent_ram_zap(prz);
425 424
426 return 0; 425 return 0;
@@ -428,19 +427,25 @@ static int __init persistent_ram_post_init(struct persistent_ram_zone *prz, bool
428 427
429void persistent_ram_free(struct persistent_ram_zone *prz) 428void persistent_ram_free(struct persistent_ram_zone *prz)
430{ 429{
431 if (pfn_valid(prz->paddr >> PAGE_SHIFT)) { 430 if (!prz)
432 vunmap(prz->vaddr); 431 return;
433 } else { 432
434 iounmap(prz->vaddr); 433 if (prz->vaddr) {
435 release_mem_region(prz->paddr, prz->size); 434 if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
435 vunmap(prz->vaddr);
436 } else {
437 iounmap(prz->vaddr);
438 release_mem_region(prz->paddr, prz->size);
439 }
440 prz->vaddr = NULL;
436 } 441 }
437 persistent_ram_free_old(prz); 442 persistent_ram_free_old(prz);
438 kfree(prz); 443 kfree(prz);
439} 444}
440 445
441struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start, 446struct persistent_ram_zone * __devinit persistent_ram_new(phys_addr_t start,
442 size_t size, 447 size_t size, u32 sig,
443 bool ecc) 448 int ecc_size)
444{ 449{
445 struct persistent_ram_zone *prz; 450 struct persistent_ram_zone *prz;
446 int ret = -ENOMEM; 451 int ret = -ENOMEM;
@@ -455,85 +460,12 @@ struct persistent_ram_zone * __init persistent_ram_new(phys_addr_t start,
455 if (ret) 460 if (ret)
456 goto err; 461 goto err;
457 462
458 persistent_ram_post_init(prz, ecc); 463 ret = persistent_ram_post_init(prz, sig, ecc_size);
459 464 if (ret)
460 return prz;
461err:
462 kfree(prz);
463 return ERR_PTR(ret);
464}
465
466#ifndef MODULE
467static int __init persistent_ram_buffer_init(const char *name,
468 struct persistent_ram_zone *prz)
469{
470 int i;
471 struct persistent_ram *ram;
472 struct persistent_ram_descriptor *desc;
473 phys_addr_t start;
474
475 list_for_each_entry(ram, &persistent_ram_list, node) {
476 start = ram->start;
477 for (i = 0; i < ram->num_descs; i++) {
478 desc = &ram->descs[i];
479 if (!strcmp(desc->name, name))
480 return persistent_ram_buffer_map(start,
481 desc->size, prz);
482 start += desc->size;
483 }
484 }
485
486 return -EINVAL;
487}
488
489static __init
490struct persistent_ram_zone *__persistent_ram_init(struct device *dev, bool ecc)
491{
492 struct persistent_ram_zone *prz;
493 int ret = -ENOMEM;
494
495 prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
496 if (!prz) {
497 pr_err("persistent_ram: failed to allocate persistent ram zone\n");
498 goto err;
499 }
500
501 ret = persistent_ram_buffer_init(dev_name(dev), prz);
502 if (ret) {
503 pr_err("persistent_ram: failed to initialize buffer\n");
504 goto err; 465 goto err;
505 }
506
507 persistent_ram_post_init(prz, ecc);
508 466
509 return prz; 467 return prz;
510err: 468err:
511 kfree(prz); 469 persistent_ram_free(prz);
512 return ERR_PTR(ret); 470 return ERR_PTR(ret);
513} 471}
514
515struct persistent_ram_zone * __init
516persistent_ram_init_ringbuffer(struct device *dev, bool ecc)
517{
518 return __persistent_ram_init(dev, ecc);
519}
520
521int __init persistent_ram_early_init(struct persistent_ram *ram)
522{
523 int ret;
524
525 ret = memblock_reserve(ram->start, ram->size);
526 if (ret) {
527 pr_err("Failed to reserve persistent memory from %08lx-%08lx\n",
528 (long)ram->start, (long)(ram->start + ram->size - 1));
529 return ret;
530 }
531
532 list_add_tail(&ram->node, &persistent_ram_list);
533
534 pr_info("Initialized persistent memory from %08lx-%08lx\n",
535 (long)ram->start, (long)(ram->start + ram->size - 1));
536
537 return 0;
538}
539#endif