Commit bd08ec33b5c23833581e5a36b2a69ccae6b39a28

Authored by Arve Hjønnevåg
Committed by Anton Vorontsov
1 parent c31ad081e8

pstore/ram: Restore ecc information block

This was lost when proc/last_kmsg moved to pstore/console-ramoops.

Signed-off-by: Arve Hjønnevåg <arve@android.com>
Signed-off-by: John Stultz <john.stultz@linaro.org>
Acked-by: Kees Cook <keescook@chromium.org>
Signed-off-by: Anton Vorontsov <anton@enomsg.org>

Showing 2 changed files with 13 additions and 2 deletions Inline Diff

1 /* 1 /*
2 * RAM Oops/Panic logger 2 * RAM Oops/Panic logger
3 * 3 *
4 * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com> 4 * Copyright (C) 2010 Marco Stornelli <marco.stornelli@gmail.com>
5 * Copyright (C) 2011 Kees Cook <keescook@chromium.org> 5 * Copyright (C) 2011 Kees Cook <keescook@chromium.org>
6 * 6 *
7 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License 8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation. 9 * version 2 as published by the Free Software Foundation.
10 * 10 *
11 * This program is distributed in the hope that it will be useful, but 11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of 12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details. 14 * General Public License for more details.
15 * 15 *
16 * You should have received a copy of the GNU General Public License 16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software 17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
19 * 02110-1301 USA 19 * 02110-1301 USA
20 * 20 *
21 */ 21 */
22 22
23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
24 24
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/version.h>
29 #include <linux/pstore.h> 29 #include <linux/pstore.h>
30 #include <linux/time.h> 30 #include <linux/time.h>
31 #include <linux/io.h> 31 #include <linux/io.h>
32 #include <linux/ioport.h> 32 #include <linux/ioport.h>
33 #include <linux/platform_device.h> 33 #include <linux/platform_device.h>
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 37
38 #define RAMOOPS_KERNMSG_HDR "====" 38 #define RAMOOPS_KERNMSG_HDR "===="
39 #define MIN_MEM_SIZE 4096UL 39 #define MIN_MEM_SIZE 4096UL
40 40
41 static ulong record_size = MIN_MEM_SIZE; 41 static ulong record_size = MIN_MEM_SIZE;
42 module_param(record_size, ulong, 0400); 42 module_param(record_size, ulong, 0400);
43 MODULE_PARM_DESC(record_size, 43 MODULE_PARM_DESC(record_size,
44 "size of each dump done on oops/panic"); 44 "size of each dump done on oops/panic");
45 45
46 static ulong ramoops_console_size = MIN_MEM_SIZE; 46 static ulong ramoops_console_size = MIN_MEM_SIZE;
47 module_param_named(console_size, ramoops_console_size, ulong, 0400); 47 module_param_named(console_size, ramoops_console_size, ulong, 0400);
48 MODULE_PARM_DESC(console_size, "size of kernel console log"); 48 MODULE_PARM_DESC(console_size, "size of kernel console log");
49 49
50 static ulong ramoops_ftrace_size = MIN_MEM_SIZE; 50 static ulong ramoops_ftrace_size = MIN_MEM_SIZE;
51 module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400); 51 module_param_named(ftrace_size, ramoops_ftrace_size, ulong, 0400);
52 MODULE_PARM_DESC(ftrace_size, "size of ftrace log"); 52 MODULE_PARM_DESC(ftrace_size, "size of ftrace log");
53 53
54 static ulong mem_address; 54 static ulong mem_address;
55 module_param(mem_address, ulong, 0400); 55 module_param(mem_address, ulong, 0400);
56 MODULE_PARM_DESC(mem_address, 56 MODULE_PARM_DESC(mem_address,
57 "start of reserved RAM used to store oops/panic logs"); 57 "start of reserved RAM used to store oops/panic logs");
58 58
59 static ulong mem_size; 59 static ulong mem_size;
60 module_param(mem_size, ulong, 0400); 60 module_param(mem_size, ulong, 0400);
61 MODULE_PARM_DESC(mem_size, 61 MODULE_PARM_DESC(mem_size,
62 "size of reserved RAM used to store oops/panic logs"); 62 "size of reserved RAM used to store oops/panic logs");
63 63
64 static int dump_oops = 1; 64 static int dump_oops = 1;
65 module_param(dump_oops, int, 0600); 65 module_param(dump_oops, int, 0600);
66 MODULE_PARM_DESC(dump_oops, 66 MODULE_PARM_DESC(dump_oops,
67 "set to 1 to dump oopses, 0 to only dump panics (default 1)"); 67 "set to 1 to dump oopses, 0 to only dump panics (default 1)");
68 68
69 static int ramoops_ecc; 69 static int ramoops_ecc;
70 module_param_named(ecc, ramoops_ecc, int, 0600); 70 module_param_named(ecc, ramoops_ecc, int, 0600);
71 MODULE_PARM_DESC(ramoops_ecc, 71 MODULE_PARM_DESC(ramoops_ecc,
72 "if non-zero, the option enables ECC support and specifies " 72 "if non-zero, the option enables ECC support and specifies "
73 "ECC buffer size in bytes (1 is a special value, means 16 " 73 "ECC buffer size in bytes (1 is a special value, means 16 "
74 "bytes ECC)"); 74 "bytes ECC)");
75 75
76 struct ramoops_context { 76 struct ramoops_context {
77 struct persistent_ram_zone **przs; 77 struct persistent_ram_zone **przs;
78 struct persistent_ram_zone *cprz; 78 struct persistent_ram_zone *cprz;
79 struct persistent_ram_zone *fprz; 79 struct persistent_ram_zone *fprz;
80 phys_addr_t phys_addr; 80 phys_addr_t phys_addr;
81 unsigned long size; 81 unsigned long size;
82 size_t record_size; 82 size_t record_size;
83 size_t console_size; 83 size_t console_size;
84 size_t ftrace_size; 84 size_t ftrace_size;
85 int dump_oops; 85 int dump_oops;
86 struct persistent_ram_ecc_info ecc_info; 86 struct persistent_ram_ecc_info ecc_info;
87 unsigned int max_dump_cnt; 87 unsigned int max_dump_cnt;
88 unsigned int dump_write_cnt; 88 unsigned int dump_write_cnt;
89 unsigned int dump_read_cnt; 89 unsigned int dump_read_cnt;
90 unsigned int console_read_cnt; 90 unsigned int console_read_cnt;
91 unsigned int ftrace_read_cnt; 91 unsigned int ftrace_read_cnt;
92 struct pstore_info pstore; 92 struct pstore_info pstore;
93 }; 93 };
94 94
95 static struct platform_device *dummy; 95 static struct platform_device *dummy;
96 static struct ramoops_platform_data *dummy_data; 96 static struct ramoops_platform_data *dummy_data;
97 97
98 static int ramoops_pstore_open(struct pstore_info *psi) 98 static int ramoops_pstore_open(struct pstore_info *psi)
99 { 99 {
100 struct ramoops_context *cxt = psi->data; 100 struct ramoops_context *cxt = psi->data;
101 101
102 cxt->dump_read_cnt = 0; 102 cxt->dump_read_cnt = 0;
103 cxt->console_read_cnt = 0; 103 cxt->console_read_cnt = 0;
104 return 0; 104 return 0;
105 } 105 }
106 106
107 static struct persistent_ram_zone * 107 static struct persistent_ram_zone *
108 ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max, 108 ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
109 u64 *id, 109 u64 *id,
110 enum pstore_type_id *typep, enum pstore_type_id type, 110 enum pstore_type_id *typep, enum pstore_type_id type,
111 bool update) 111 bool update)
112 { 112 {
113 struct persistent_ram_zone *prz; 113 struct persistent_ram_zone *prz;
114 int i = (*c)++; 114 int i = (*c)++;
115 115
116 if (i >= max) 116 if (i >= max)
117 return NULL; 117 return NULL;
118 118
119 prz = przs[i]; 119 prz = przs[i];
120 120
121 if (update) { 121 if (update) {
122 /* Update old/shadowed buffer. */ 122 /* Update old/shadowed buffer. */
123 persistent_ram_save_old(prz); 123 persistent_ram_save_old(prz);
124 if (!persistent_ram_old_size(prz)) 124 if (!persistent_ram_old_size(prz))
125 return NULL; 125 return NULL;
126 } 126 }
127 127
128 *typep = type; 128 *typep = type;
129 *id = i; 129 *id = i;
130 130
131 return prz; 131 return prz;
132 } 132 }
133 133
134 static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type, 134 static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
135 int *count, struct timespec *time, 135 int *count, struct timespec *time,
136 char **buf, struct pstore_info *psi) 136 char **buf, struct pstore_info *psi)
137 { 137 {
138 ssize_t size; 138 ssize_t size;
139 ssize_t ecc_notice_size;
139 struct ramoops_context *cxt = psi->data; 140 struct ramoops_context *cxt = psi->data;
140 struct persistent_ram_zone *prz; 141 struct persistent_ram_zone *prz;
141 142
142 prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt, 143 prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
143 cxt->max_dump_cnt, id, type, 144 cxt->max_dump_cnt, id, type,
144 PSTORE_TYPE_DMESG, 1); 145 PSTORE_TYPE_DMESG, 1);
145 if (!prz) 146 if (!prz)
146 prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt, 147 prz = ramoops_get_next_prz(&cxt->cprz, &cxt->console_read_cnt,
147 1, id, type, PSTORE_TYPE_CONSOLE, 0); 148 1, id, type, PSTORE_TYPE_CONSOLE, 0);
148 if (!prz) 149 if (!prz)
149 prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt, 150 prz = ramoops_get_next_prz(&cxt->fprz, &cxt->ftrace_read_cnt,
150 1, id, type, PSTORE_TYPE_FTRACE, 0); 151 1, id, type, PSTORE_TYPE_FTRACE, 0);
151 if (!prz) 152 if (!prz)
152 return 0; 153 return 0;
153 154
154 /* TODO(kees): Bogus time for the moment. */ 155 /* TODO(kees): Bogus time for the moment. */
155 time->tv_sec = 0; 156 time->tv_sec = 0;
156 time->tv_nsec = 0; 157 time->tv_nsec = 0;
157 158
158 size = persistent_ram_old_size(prz); 159 size = persistent_ram_old_size(prz);
159 *buf = kmemdup(persistent_ram_old(prz), size, GFP_KERNEL); 160
161 /* ECC correction notice */
162 ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
163
164 *buf = kmalloc(size + ecc_notice_size + 1, GFP_KERNEL);
160 if (*buf == NULL) 165 if (*buf == NULL)
161 return -ENOMEM; 166 return -ENOMEM;
162 167
163 return size; 168 memcpy(*buf, persistent_ram_old(prz), size);
169 persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
170
171 return size + ecc_notice_size;
164 } 172 }
165 173
166 static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz) 174 static size_t ramoops_write_kmsg_hdr(struct persistent_ram_zone *prz)
167 { 175 {
168 char *hdr; 176 char *hdr;
169 struct timespec timestamp; 177 struct timespec timestamp;
170 size_t len; 178 size_t len;
171 179
172 /* Report zeroed timestamp if called before timekeeping has resumed. */ 180 /* Report zeroed timestamp if called before timekeeping has resumed. */
173 if (__getnstimeofday(&timestamp)) { 181 if (__getnstimeofday(&timestamp)) {
174 timestamp.tv_sec = 0; 182 timestamp.tv_sec = 0;
175 timestamp.tv_nsec = 0; 183 timestamp.tv_nsec = 0;
176 } 184 }
177 hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n", 185 hdr = kasprintf(GFP_ATOMIC, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
178 (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000)); 186 (long)timestamp.tv_sec, (long)(timestamp.tv_nsec / 1000));
179 WARN_ON_ONCE(!hdr); 187 WARN_ON_ONCE(!hdr);
180 len = hdr ? strlen(hdr) : 0; 188 len = hdr ? strlen(hdr) : 0;
181 persistent_ram_write(prz, hdr, len); 189 persistent_ram_write(prz, hdr, len);
182 kfree(hdr); 190 kfree(hdr);
183 191
184 return len; 192 return len;
185 } 193 }
186 194
187 static int notrace ramoops_pstore_write_buf(enum pstore_type_id type, 195 static int notrace ramoops_pstore_write_buf(enum pstore_type_id type,
188 enum kmsg_dump_reason reason, 196 enum kmsg_dump_reason reason,
189 u64 *id, unsigned int part, 197 u64 *id, unsigned int part,
190 const char *buf, size_t size, 198 const char *buf, size_t size,
191 struct pstore_info *psi) 199 struct pstore_info *psi)
192 { 200 {
193 struct ramoops_context *cxt = psi->data; 201 struct ramoops_context *cxt = psi->data;
194 struct persistent_ram_zone *prz; 202 struct persistent_ram_zone *prz;
195 size_t hlen; 203 size_t hlen;
196 204
197 if (type == PSTORE_TYPE_CONSOLE) { 205 if (type == PSTORE_TYPE_CONSOLE) {
198 if (!cxt->cprz) 206 if (!cxt->cprz)
199 return -ENOMEM; 207 return -ENOMEM;
200 persistent_ram_write(cxt->cprz, buf, size); 208 persistent_ram_write(cxt->cprz, buf, size);
201 return 0; 209 return 0;
202 } else if (type == PSTORE_TYPE_FTRACE) { 210 } else if (type == PSTORE_TYPE_FTRACE) {
203 if (!cxt->fprz) 211 if (!cxt->fprz)
204 return -ENOMEM; 212 return -ENOMEM;
205 persistent_ram_write(cxt->fprz, buf, size); 213 persistent_ram_write(cxt->fprz, buf, size);
206 return 0; 214 return 0;
207 } 215 }
208 216
209 if (type != PSTORE_TYPE_DMESG) 217 if (type != PSTORE_TYPE_DMESG)
210 return -EINVAL; 218 return -EINVAL;
211 219
212 /* Out of the various dmesg dump types, ramoops is currently designed 220 /* Out of the various dmesg dump types, ramoops is currently designed
213 * to only store crash logs, rather than storing general kernel logs. 221 * to only store crash logs, rather than storing general kernel logs.
214 */ 222 */
215 if (reason != KMSG_DUMP_OOPS && 223 if (reason != KMSG_DUMP_OOPS &&
216 reason != KMSG_DUMP_PANIC) 224 reason != KMSG_DUMP_PANIC)
217 return -EINVAL; 225 return -EINVAL;
218 226
219 /* Skip Oopes when configured to do so. */ 227 /* Skip Oopes when configured to do so. */
220 if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops) 228 if (reason == KMSG_DUMP_OOPS && !cxt->dump_oops)
221 return -EINVAL; 229 return -EINVAL;
222 230
223 /* Explicitly only take the first part of any new crash. 231 /* Explicitly only take the first part of any new crash.
224 * If our buffer is larger than kmsg_bytes, this can never happen, 232 * If our buffer is larger than kmsg_bytes, this can never happen,
225 * and if our buffer is smaller than kmsg_bytes, we don't want the 233 * and if our buffer is smaller than kmsg_bytes, we don't want the
226 * report split across multiple records. 234 * report split across multiple records.
227 */ 235 */
228 if (part != 1) 236 if (part != 1)
229 return -ENOSPC; 237 return -ENOSPC;
230 238
231 if (!cxt->przs) 239 if (!cxt->przs)
232 return -ENOSPC; 240 return -ENOSPC;
233 241
234 prz = cxt->przs[cxt->dump_write_cnt]; 242 prz = cxt->przs[cxt->dump_write_cnt];
235 243
236 hlen = ramoops_write_kmsg_hdr(prz); 244 hlen = ramoops_write_kmsg_hdr(prz);
237 if (size + hlen > prz->buffer_size) 245 if (size + hlen > prz->buffer_size)
238 size = prz->buffer_size - hlen; 246 size = prz->buffer_size - hlen;
239 persistent_ram_write(prz, buf, size); 247 persistent_ram_write(prz, buf, size);
240 248
241 cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt; 249 cxt->dump_write_cnt = (cxt->dump_write_cnt + 1) % cxt->max_dump_cnt;
242 250
243 return 0; 251 return 0;
244 } 252 }
245 253
246 static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count, 254 static int ramoops_pstore_erase(enum pstore_type_id type, u64 id, int count,
247 struct timespec time, struct pstore_info *psi) 255 struct timespec time, struct pstore_info *psi)
248 { 256 {
249 struct ramoops_context *cxt = psi->data; 257 struct ramoops_context *cxt = psi->data;
250 struct persistent_ram_zone *prz; 258 struct persistent_ram_zone *prz;
251 259
252 switch (type) { 260 switch (type) {
253 case PSTORE_TYPE_DMESG: 261 case PSTORE_TYPE_DMESG:
254 if (id >= cxt->max_dump_cnt) 262 if (id >= cxt->max_dump_cnt)
255 return -EINVAL; 263 return -EINVAL;
256 prz = cxt->przs[id]; 264 prz = cxt->przs[id];
257 break; 265 break;
258 case PSTORE_TYPE_CONSOLE: 266 case PSTORE_TYPE_CONSOLE:
259 prz = cxt->cprz; 267 prz = cxt->cprz;
260 break; 268 break;
261 case PSTORE_TYPE_FTRACE: 269 case PSTORE_TYPE_FTRACE:
262 prz = cxt->fprz; 270 prz = cxt->fprz;
263 break; 271 break;
264 default: 272 default:
265 return -EINVAL; 273 return -EINVAL;
266 } 274 }
267 275
268 persistent_ram_free_old(prz); 276 persistent_ram_free_old(prz);
269 persistent_ram_zap(prz); 277 persistent_ram_zap(prz);
270 278
271 return 0; 279 return 0;
272 } 280 }
273 281
274 static struct ramoops_context oops_cxt = { 282 static struct ramoops_context oops_cxt = {
275 .pstore = { 283 .pstore = {
276 .owner = THIS_MODULE, 284 .owner = THIS_MODULE,
277 .name = "ramoops", 285 .name = "ramoops",
278 .open = ramoops_pstore_open, 286 .open = ramoops_pstore_open,
279 .read = ramoops_pstore_read, 287 .read = ramoops_pstore_read,
280 .write_buf = ramoops_pstore_write_buf, 288 .write_buf = ramoops_pstore_write_buf,
281 .erase = ramoops_pstore_erase, 289 .erase = ramoops_pstore_erase,
282 }, 290 },
283 }; 291 };
284 292
285 static void ramoops_free_przs(struct ramoops_context *cxt) 293 static void ramoops_free_przs(struct ramoops_context *cxt)
286 { 294 {
287 int i; 295 int i;
288 296
289 if (!cxt->przs) 297 if (!cxt->przs)
290 return; 298 return;
291 299
292 for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++) 300 for (i = 0; !IS_ERR_OR_NULL(cxt->przs[i]); i++)
293 persistent_ram_free(cxt->przs[i]); 301 persistent_ram_free(cxt->przs[i]);
294 kfree(cxt->przs); 302 kfree(cxt->przs);
295 } 303 }
296 304
297 static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt, 305 static int ramoops_init_przs(struct device *dev, struct ramoops_context *cxt,
298 phys_addr_t *paddr, size_t dump_mem_sz) 306 phys_addr_t *paddr, size_t dump_mem_sz)
299 { 307 {
300 int err = -ENOMEM; 308 int err = -ENOMEM;
301 int i; 309 int i;
302 310
303 if (!cxt->record_size) 311 if (!cxt->record_size)
304 return 0; 312 return 0;
305 313
306 if (*paddr + dump_mem_sz - cxt->phys_addr > cxt->size) { 314 if (*paddr + dump_mem_sz - cxt->phys_addr > cxt->size) {
307 dev_err(dev, "no room for dumps\n"); 315 dev_err(dev, "no room for dumps\n");
308 return -ENOMEM; 316 return -ENOMEM;
309 } 317 }
310 318
311 cxt->max_dump_cnt = dump_mem_sz / cxt->record_size; 319 cxt->max_dump_cnt = dump_mem_sz / cxt->record_size;
312 if (!cxt->max_dump_cnt) 320 if (!cxt->max_dump_cnt)
313 return -ENOMEM; 321 return -ENOMEM;
314 322
315 cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt, 323 cxt->przs = kzalloc(sizeof(*cxt->przs) * cxt->max_dump_cnt,
316 GFP_KERNEL); 324 GFP_KERNEL);
317 if (!cxt->przs) { 325 if (!cxt->przs) {
318 dev_err(dev, "failed to initialize a prz array for dumps\n"); 326 dev_err(dev, "failed to initialize a prz array for dumps\n");
319 return -ENOMEM; 327 return -ENOMEM;
320 } 328 }
321 329
322 for (i = 0; i < cxt->max_dump_cnt; i++) { 330 for (i = 0; i < cxt->max_dump_cnt; i++) {
323 size_t sz = cxt->record_size; 331 size_t sz = cxt->record_size;
324 332
325 cxt->przs[i] = persistent_ram_new(*paddr, sz, 0, 333 cxt->przs[i] = persistent_ram_new(*paddr, sz, 0,
326 &cxt->ecc_info); 334 &cxt->ecc_info);
327 if (IS_ERR(cxt->przs[i])) { 335 if (IS_ERR(cxt->przs[i])) {
328 err = PTR_ERR(cxt->przs[i]); 336 err = PTR_ERR(cxt->przs[i]);
329 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", 337 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
330 sz, (unsigned long long)*paddr, err); 338 sz, (unsigned long long)*paddr, err);
331 goto fail_prz; 339 goto fail_prz;
332 } 340 }
333 *paddr += sz; 341 *paddr += sz;
334 } 342 }
335 343
336 return 0; 344 return 0;
337 fail_prz: 345 fail_prz:
338 ramoops_free_przs(cxt); 346 ramoops_free_przs(cxt);
339 return err; 347 return err;
340 } 348 }
341 349
342 static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt, 350 static int ramoops_init_prz(struct device *dev, struct ramoops_context *cxt,
343 struct persistent_ram_zone **prz, 351 struct persistent_ram_zone **prz,
344 phys_addr_t *paddr, size_t sz, u32 sig) 352 phys_addr_t *paddr, size_t sz, u32 sig)
345 { 353 {
346 if (!sz) 354 if (!sz)
347 return 0; 355 return 0;
348 356
349 if (*paddr + sz - cxt->phys_addr > cxt->size) { 357 if (*paddr + sz - cxt->phys_addr > cxt->size) {
350 dev_err(dev, "no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n", 358 dev_err(dev, "no room for mem region (0x%zx@0x%llx) in (0x%lx@0x%llx)\n",
351 sz, (unsigned long long)*paddr, 359 sz, (unsigned long long)*paddr,
352 cxt->size, (unsigned long long)cxt->phys_addr); 360 cxt->size, (unsigned long long)cxt->phys_addr);
353 return -ENOMEM; 361 return -ENOMEM;
354 } 362 }
355 363
356 *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info); 364 *prz = persistent_ram_new(*paddr, sz, sig, &cxt->ecc_info);
357 if (IS_ERR(*prz)) { 365 if (IS_ERR(*prz)) {
358 int err = PTR_ERR(*prz); 366 int err = PTR_ERR(*prz);
359 367
360 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n", 368 dev_err(dev, "failed to request mem region (0x%zx@0x%llx): %d\n",
361 sz, (unsigned long long)*paddr, err); 369 sz, (unsigned long long)*paddr, err);
362 return err; 370 return err;
363 } 371 }
364 372
365 persistent_ram_zap(*prz); 373 persistent_ram_zap(*prz);
366 374
367 *paddr += sz; 375 *paddr += sz;
368 376
369 return 0; 377 return 0;
370 } 378 }
371 379
372 static int ramoops_probe(struct platform_device *pdev) 380 static int ramoops_probe(struct platform_device *pdev)
373 { 381 {
374 struct device *dev = &pdev->dev; 382 struct device *dev = &pdev->dev;
375 struct ramoops_platform_data *pdata = pdev->dev.platform_data; 383 struct ramoops_platform_data *pdata = pdev->dev.platform_data;
376 struct ramoops_context *cxt = &oops_cxt; 384 struct ramoops_context *cxt = &oops_cxt;
377 size_t dump_mem_sz; 385 size_t dump_mem_sz;
378 phys_addr_t paddr; 386 phys_addr_t paddr;
379 int err = -EINVAL; 387 int err = -EINVAL;
380 388
381 /* Only a single ramoops area allowed at a time, so fail extra 389 /* Only a single ramoops area allowed at a time, so fail extra
382 * probes. 390 * probes.
383 */ 391 */
384 if (cxt->max_dump_cnt) 392 if (cxt->max_dump_cnt)
385 goto fail_out; 393 goto fail_out;
386 394
387 if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size && 395 if (!pdata->mem_size || (!pdata->record_size && !pdata->console_size &&
388 !pdata->ftrace_size)) { 396 !pdata->ftrace_size)) {
389 pr_err("The memory size and the record/console size must be " 397 pr_err("The memory size and the record/console size must be "
390 "non-zero\n"); 398 "non-zero\n");
391 goto fail_out; 399 goto fail_out;
392 } 400 }
393 401
394 if (!is_power_of_2(pdata->mem_size)) 402 if (!is_power_of_2(pdata->mem_size))
395 pdata->mem_size = rounddown_pow_of_two(pdata->mem_size); 403 pdata->mem_size = rounddown_pow_of_two(pdata->mem_size);
396 if (!is_power_of_2(pdata->record_size)) 404 if (!is_power_of_2(pdata->record_size))
397 pdata->record_size = rounddown_pow_of_two(pdata->record_size); 405 pdata->record_size = rounddown_pow_of_two(pdata->record_size);
398 if (!is_power_of_2(pdata->console_size)) 406 if (!is_power_of_2(pdata->console_size))
399 pdata->console_size = rounddown_pow_of_two(pdata->console_size); 407 pdata->console_size = rounddown_pow_of_two(pdata->console_size);
400 if (!is_power_of_2(pdata->ftrace_size)) 408 if (!is_power_of_2(pdata->ftrace_size))
401 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size); 409 pdata->ftrace_size = rounddown_pow_of_two(pdata->ftrace_size);
402 410
403 cxt->dump_read_cnt = 0; 411 cxt->dump_read_cnt = 0;
404 cxt->size = pdata->mem_size; 412 cxt->size = pdata->mem_size;
405 cxt->phys_addr = pdata->mem_address; 413 cxt->phys_addr = pdata->mem_address;
406 cxt->record_size = pdata->record_size; 414 cxt->record_size = pdata->record_size;
407 cxt->console_size = pdata->console_size; 415 cxt->console_size = pdata->console_size;
408 cxt->ftrace_size = pdata->ftrace_size; 416 cxt->ftrace_size = pdata->ftrace_size;
409 cxt->dump_oops = pdata->dump_oops; 417 cxt->dump_oops = pdata->dump_oops;
410 cxt->ecc_info = pdata->ecc_info; 418 cxt->ecc_info = pdata->ecc_info;
411 419
412 paddr = cxt->phys_addr; 420 paddr = cxt->phys_addr;
413 421
414 dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size; 422 dump_mem_sz = cxt->size - cxt->console_size - cxt->ftrace_size;
415 err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz); 423 err = ramoops_init_przs(dev, cxt, &paddr, dump_mem_sz);
416 if (err) 424 if (err)
417 goto fail_out; 425 goto fail_out;
418 426
419 err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr, 427 err = ramoops_init_prz(dev, cxt, &cxt->cprz, &paddr,
420 cxt->console_size, 0); 428 cxt->console_size, 0);
421 if (err) 429 if (err)
422 goto fail_init_cprz; 430 goto fail_init_cprz;
423 431
424 err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size, 432 err = ramoops_init_prz(dev, cxt, &cxt->fprz, &paddr, cxt->ftrace_size,
425 LINUX_VERSION_CODE); 433 LINUX_VERSION_CODE);
426 if (err) 434 if (err)
427 goto fail_init_fprz; 435 goto fail_init_fprz;
428 436
429 if (!cxt->przs && !cxt->cprz && !cxt->fprz) { 437 if (!cxt->przs && !cxt->cprz && !cxt->fprz) {
430 pr_err("memory size too small, minimum is %zu\n", 438 pr_err("memory size too small, minimum is %zu\n",
431 cxt->console_size + cxt->record_size + 439 cxt->console_size + cxt->record_size +
432 cxt->ftrace_size); 440 cxt->ftrace_size);
433 goto fail_cnt; 441 goto fail_cnt;
434 } 442 }
435 443
436 cxt->pstore.data = cxt; 444 cxt->pstore.data = cxt;
437 /* 445 /*
438 * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we 446 * Console can handle any buffer size, so prefer LOG_LINE_MAX. If we
439 * have to handle dumps, we must have at least record_size buffer. And 447 * have to handle dumps, we must have at least record_size buffer. And
440 * for ftrace, bufsize is irrelevant (if bufsize is 0, buf will be 448 * for ftrace, bufsize is irrelevant (if bufsize is 0, buf will be
441 * ZERO_SIZE_PTR). 449 * ZERO_SIZE_PTR).
442 */ 450 */
443 if (cxt->console_size) 451 if (cxt->console_size)
444 cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */ 452 cxt->pstore.bufsize = 1024; /* LOG_LINE_MAX */
445 cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize); 453 cxt->pstore.bufsize = max(cxt->record_size, cxt->pstore.bufsize);
446 cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL); 454 cxt->pstore.buf = kmalloc(cxt->pstore.bufsize, GFP_KERNEL);
447 spin_lock_init(&cxt->pstore.buf_lock); 455 spin_lock_init(&cxt->pstore.buf_lock);
448 if (!cxt->pstore.buf) { 456 if (!cxt->pstore.buf) {
449 pr_err("cannot allocate pstore buffer\n"); 457 pr_err("cannot allocate pstore buffer\n");
450 goto fail_clear; 458 goto fail_clear;
451 } 459 }
452 460
453 err = pstore_register(&cxt->pstore); 461 err = pstore_register(&cxt->pstore);
454 if (err) { 462 if (err) {
455 pr_err("registering with pstore failed\n"); 463 pr_err("registering with pstore failed\n");
456 goto fail_buf; 464 goto fail_buf;
457 } 465 }
458 466
459 /* 467 /*
460 * Update the module parameter variables as well so they are visible 468 * Update the module parameter variables as well so they are visible
461 * through /sys/module/ramoops/parameters/ 469 * through /sys/module/ramoops/parameters/
462 */ 470 */
463 mem_size = pdata->mem_size; 471 mem_size = pdata->mem_size;
464 mem_address = pdata->mem_address; 472 mem_address = pdata->mem_address;
465 record_size = pdata->record_size; 473 record_size = pdata->record_size;
466 dump_oops = pdata->dump_oops; 474 dump_oops = pdata->dump_oops;
467 475
468 pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n", 476 pr_info("attached 0x%lx@0x%llx, ecc: %d/%d\n",
469 cxt->size, (unsigned long long)cxt->phys_addr, 477 cxt->size, (unsigned long long)cxt->phys_addr,
470 cxt->ecc_info.ecc_size, cxt->ecc_info.block_size); 478 cxt->ecc_info.ecc_size, cxt->ecc_info.block_size);
471 479
472 return 0; 480 return 0;
473 481
474 fail_buf: 482 fail_buf:
475 kfree(cxt->pstore.buf); 483 kfree(cxt->pstore.buf);
476 fail_clear: 484 fail_clear:
477 cxt->pstore.bufsize = 0; 485 cxt->pstore.bufsize = 0;
478 cxt->max_dump_cnt = 0; 486 cxt->max_dump_cnt = 0;
479 fail_cnt: 487 fail_cnt:
480 kfree(cxt->fprz); 488 kfree(cxt->fprz);
481 fail_init_fprz: 489 fail_init_fprz:
482 kfree(cxt->cprz); 490 kfree(cxt->cprz);
483 fail_init_cprz: 491 fail_init_cprz:
484 ramoops_free_przs(cxt); 492 ramoops_free_przs(cxt);
485 fail_out: 493 fail_out:
486 return err; 494 return err;
487 } 495 }
488 496
489 static int __exit ramoops_remove(struct platform_device *pdev) 497 static int __exit ramoops_remove(struct platform_device *pdev)
490 { 498 {
491 #if 0 499 #if 0
492 /* TODO(kees): We cannot unload ramoops since pstore doesn't support 500 /* TODO(kees): We cannot unload ramoops since pstore doesn't support
493 * unregistering yet. 501 * unregistering yet.
494 */ 502 */
495 struct ramoops_context *cxt = &oops_cxt; 503 struct ramoops_context *cxt = &oops_cxt;
496 504
497 iounmap(cxt->virt_addr); 505 iounmap(cxt->virt_addr);
498 release_mem_region(cxt->phys_addr, cxt->size); 506 release_mem_region(cxt->phys_addr, cxt->size);
499 cxt->max_dump_cnt = 0; 507 cxt->max_dump_cnt = 0;
500 508
501 /* TODO(kees): When pstore supports unregistering, call it here. */ 509 /* TODO(kees): When pstore supports unregistering, call it here. */
502 kfree(cxt->pstore.buf); 510 kfree(cxt->pstore.buf);
503 cxt->pstore.bufsize = 0; 511 cxt->pstore.bufsize = 0;
504 512
505 return 0; 513 return 0;
506 #endif 514 #endif
507 return -EBUSY; 515 return -EBUSY;
508 } 516 }
509 517
510 static struct platform_driver ramoops_driver = { 518 static struct platform_driver ramoops_driver = {
511 .probe = ramoops_probe, 519 .probe = ramoops_probe,
512 .remove = __exit_p(ramoops_remove), 520 .remove = __exit_p(ramoops_remove),
513 .driver = { 521 .driver = {
514 .name = "ramoops", 522 .name = "ramoops",
515 .owner = THIS_MODULE, 523 .owner = THIS_MODULE,
516 }, 524 },
517 }; 525 };
518 526
519 static void ramoops_register_dummy(void) 527 static void ramoops_register_dummy(void)
520 { 528 {
521 if (!mem_size) 529 if (!mem_size)
522 return; 530 return;
523 531
524 pr_info("using module parameters\n"); 532 pr_info("using module parameters\n");
525 533
526 dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL); 534 dummy_data = kzalloc(sizeof(*dummy_data), GFP_KERNEL);
527 if (!dummy_data) { 535 if (!dummy_data) {
528 pr_info("could not allocate pdata\n"); 536 pr_info("could not allocate pdata\n");
529 return; 537 return;
530 } 538 }
531 539
532 dummy_data->mem_size = mem_size; 540 dummy_data->mem_size = mem_size;
533 dummy_data->mem_address = mem_address; 541 dummy_data->mem_address = mem_address;
534 dummy_data->record_size = record_size; 542 dummy_data->record_size = record_size;
535 dummy_data->console_size = ramoops_console_size; 543 dummy_data->console_size = ramoops_console_size;
536 dummy_data->ftrace_size = ramoops_ftrace_size; 544 dummy_data->ftrace_size = ramoops_ftrace_size;
537 dummy_data->dump_oops = dump_oops; 545 dummy_data->dump_oops = dump_oops;
538 /* 546 /*
539 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC 547 * For backwards compatibility ramoops.ecc=1 means 16 bytes ECC
540 * (using 1 byte for ECC isn't much of use anyway). 548 * (using 1 byte for ECC isn't much of use anyway).
541 */ 549 */
542 dummy_data->ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc; 550 dummy_data->ecc_info.ecc_size = ramoops_ecc == 1 ? 16 : ramoops_ecc;
543 551
544 dummy = platform_device_register_data(NULL, "ramoops", -1, 552 dummy = platform_device_register_data(NULL, "ramoops", -1,
545 dummy_data, sizeof(struct ramoops_platform_data)); 553 dummy_data, sizeof(struct ramoops_platform_data));
546 if (IS_ERR(dummy)) { 554 if (IS_ERR(dummy)) {
547 pr_info("could not create platform device: %ld\n", 555 pr_info("could not create platform device: %ld\n",
548 PTR_ERR(dummy)); 556 PTR_ERR(dummy));
549 } 557 }
550 } 558 }
551 559
552 static int __init ramoops_init(void) 560 static int __init ramoops_init(void)
553 { 561 {
554 ramoops_register_dummy(); 562 ramoops_register_dummy();
555 return platform_driver_register(&ramoops_driver); 563 return platform_driver_register(&ramoops_driver);
556 } 564 }
557 postcore_initcall(ramoops_init); 565 postcore_initcall(ramoops_init);
558 566
559 static void __exit ramoops_exit(void) 567 static void __exit ramoops_exit(void)
560 { 568 {
561 platform_driver_unregister(&ramoops_driver); 569 platform_driver_unregister(&ramoops_driver);
562 platform_device_unregister(dummy); 570 platform_device_unregister(dummy);
563 kfree(dummy_data); 571 kfree(dummy_data);
564 } 572 }
565 module_exit(ramoops_exit); 573 module_exit(ramoops_exit);
566 574
567 MODULE_LICENSE("GPL"); 575 MODULE_LICENSE("GPL");
568 MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>"); 576 MODULE_AUTHOR("Marco Stornelli <marco.stornelli@gmail.com>");
569 MODULE_DESCRIPTION("RAM Oops/Panic logger/driver"); 577 MODULE_DESCRIPTION("RAM Oops/Panic logger/driver");
570 578
fs/pstore/ram_core.c
1 /* 1 /*
2 * Copyright (C) 2012 Google, Inc. 2 * Copyright (C) 2012 Google, Inc.
3 * 3 *
4 * This software is licensed under the terms of the GNU General Public 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 5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms. 6 * may be copied, distributed, and modified under those terms.
7 * 7 *
8 * This program is distributed in the hope that it will be useful, 8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details. 11 * GNU General Public License for more details.
12 * 12 *
13 */ 13 */
14 14
15 #include <linux/device.h> 15 #include <linux/device.h>
16 #include <linux/err.h> 16 #include <linux/err.h>
17 #include <linux/errno.h> 17 #include <linux/errno.h>
18 #include <linux/kernel.h> 18 #include <linux/kernel.h>
19 #include <linux/init.h> 19 #include <linux/init.h>
20 #include <linux/io.h> 20 #include <linux/io.h>
21 #include <linux/list.h> 21 #include <linux/list.h>
22 #include <linux/memblock.h> 22 #include <linux/memblock.h>
23 #include <linux/rslib.h> 23 #include <linux/rslib.h>
24 #include <linux/slab.h> 24 #include <linux/slab.h>
25 #include <linux/vmalloc.h> 25 #include <linux/vmalloc.h>
26 #include <linux/pstore_ram.h> 26 #include <linux/pstore_ram.h>
27 #include <asm/page.h> 27 #include <asm/page.h>
28 28
29 struct persistent_ram_buffer { 29 struct persistent_ram_buffer {
30 uint32_t sig; 30 uint32_t sig;
31 atomic_t start; 31 atomic_t start;
32 atomic_t size; 32 atomic_t size;
33 uint8_t data[0]; 33 uint8_t data[0];
34 }; 34 };
35 35
36 #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */ 36 #define PERSISTENT_RAM_SIG (0x43474244) /* DBGC */
37 37
38 static inline size_t buffer_size(struct persistent_ram_zone *prz) 38 static inline size_t buffer_size(struct persistent_ram_zone *prz)
39 { 39 {
40 return atomic_read(&prz->buffer->size); 40 return atomic_read(&prz->buffer->size);
41 } 41 }
42 42
43 static inline size_t buffer_start(struct persistent_ram_zone *prz) 43 static inline size_t buffer_start(struct persistent_ram_zone *prz)
44 { 44 {
45 return atomic_read(&prz->buffer->start); 45 return atomic_read(&prz->buffer->start);
46 } 46 }
47 47
48 /* increase and wrap the start pointer, returning the old value */ 48 /* increase and wrap the start pointer, returning the old value */
49 static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a) 49 static inline size_t buffer_start_add(struct persistent_ram_zone *prz, size_t a)
50 { 50 {
51 int old; 51 int old;
52 int new; 52 int new;
53 53
54 do { 54 do {
55 old = atomic_read(&prz->buffer->start); 55 old = atomic_read(&prz->buffer->start);
56 new = old + a; 56 new = old + a;
57 while (unlikely(new > prz->buffer_size)) 57 while (unlikely(new > prz->buffer_size))
58 new -= prz->buffer_size; 58 new -= prz->buffer_size;
59 } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old); 59 } while (atomic_cmpxchg(&prz->buffer->start, old, new) != old);
60 60
61 return old; 61 return old;
62 } 62 }
63 63
64 /* increase the size counter until it hits the max size */ 64 /* increase the size counter until it hits the max size */
65 static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a) 65 static inline void buffer_size_add(struct persistent_ram_zone *prz, size_t a)
66 { 66 {
67 size_t old; 67 size_t old;
68 size_t new; 68 size_t new;
69 69
70 if (atomic_read(&prz->buffer->size) == prz->buffer_size) 70 if (atomic_read(&prz->buffer->size) == prz->buffer_size)
71 return; 71 return;
72 72
73 do { 73 do {
74 old = atomic_read(&prz->buffer->size); 74 old = atomic_read(&prz->buffer->size);
75 new = old + a; 75 new = old + a;
76 if (new > prz->buffer_size) 76 if (new > prz->buffer_size)
77 new = prz->buffer_size; 77 new = prz->buffer_size;
78 } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old); 78 } while (atomic_cmpxchg(&prz->buffer->size, old, new) != old);
79 } 79 }
80 80
81 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz, 81 static void notrace persistent_ram_encode_rs8(struct persistent_ram_zone *prz,
82 uint8_t *data, size_t len, uint8_t *ecc) 82 uint8_t *data, size_t len, uint8_t *ecc)
83 { 83 {
84 int i; 84 int i;
85 uint16_t par[prz->ecc_info.ecc_size]; 85 uint16_t par[prz->ecc_info.ecc_size];
86 86
87 /* Initialize the parity buffer */ 87 /* Initialize the parity buffer */
88 memset(par, 0, sizeof(par)); 88 memset(par, 0, sizeof(par));
89 encode_rs8(prz->rs_decoder, data, len, par, 0); 89 encode_rs8(prz->rs_decoder, data, len, par, 0);
90 for (i = 0; i < prz->ecc_info.ecc_size; i++) 90 for (i = 0; i < prz->ecc_info.ecc_size; i++)
91 ecc[i] = par[i]; 91 ecc[i] = par[i];
92 } 92 }
93 93
94 static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz, 94 static int persistent_ram_decode_rs8(struct persistent_ram_zone *prz,
95 void *data, size_t len, uint8_t *ecc) 95 void *data, size_t len, uint8_t *ecc)
96 { 96 {
97 int i; 97 int i;
98 uint16_t par[prz->ecc_info.ecc_size]; 98 uint16_t par[prz->ecc_info.ecc_size];
99 99
100 for (i = 0; i < prz->ecc_info.ecc_size; i++) 100 for (i = 0; i < prz->ecc_info.ecc_size; i++)
101 par[i] = ecc[i]; 101 par[i] = ecc[i];
102 return decode_rs8(prz->rs_decoder, data, par, len, 102 return decode_rs8(prz->rs_decoder, data, par, len,
103 NULL, 0, NULL, 0, NULL); 103 NULL, 0, NULL, 0, NULL);
104 } 104 }
105 105
106 static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz, 106 static void notrace persistent_ram_update_ecc(struct persistent_ram_zone *prz,
107 unsigned int start, unsigned int count) 107 unsigned int start, unsigned int count)
108 { 108 {
109 struct persistent_ram_buffer *buffer = prz->buffer; 109 struct persistent_ram_buffer *buffer = prz->buffer;
110 uint8_t *buffer_end = buffer->data + prz->buffer_size; 110 uint8_t *buffer_end = buffer->data + prz->buffer_size;
111 uint8_t *block; 111 uint8_t *block;
112 uint8_t *par; 112 uint8_t *par;
113 int ecc_block_size = prz->ecc_info.block_size; 113 int ecc_block_size = prz->ecc_info.block_size;
114 int ecc_size = prz->ecc_info.ecc_size; 114 int ecc_size = prz->ecc_info.ecc_size;
115 int size = ecc_block_size; 115 int size = ecc_block_size;
116 116
117 if (!ecc_size) 117 if (!ecc_size)
118 return; 118 return;
119 119
120 block = buffer->data + (start & ~(ecc_block_size - 1)); 120 block = buffer->data + (start & ~(ecc_block_size - 1));
121 par = prz->par_buffer + (start / ecc_block_size) * ecc_size; 121 par = prz->par_buffer + (start / ecc_block_size) * ecc_size;
122 122
123 do { 123 do {
124 if (block + ecc_block_size > buffer_end) 124 if (block + ecc_block_size > buffer_end)
125 size = buffer_end - block; 125 size = buffer_end - block;
126 persistent_ram_encode_rs8(prz, block, size, par); 126 persistent_ram_encode_rs8(prz, block, size, par);
127 block += ecc_block_size; 127 block += ecc_block_size;
128 par += ecc_size; 128 par += ecc_size;
129 } while (block < buffer->data + start + count); 129 } while (block < buffer->data + start + count);
130 } 130 }
131 131
132 static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz) 132 static void persistent_ram_update_header_ecc(struct persistent_ram_zone *prz)
133 { 133 {
134 struct persistent_ram_buffer *buffer = prz->buffer; 134 struct persistent_ram_buffer *buffer = prz->buffer;
135 135
136 if (!prz->ecc_info.ecc_size) 136 if (!prz->ecc_info.ecc_size)
137 return; 137 return;
138 138
139 persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer), 139 persistent_ram_encode_rs8(prz, (uint8_t *)buffer, sizeof(*buffer),
140 prz->par_header); 140 prz->par_header);
141 } 141 }
142 142
143 static void persistent_ram_ecc_old(struct persistent_ram_zone *prz) 143 static void persistent_ram_ecc_old(struct persistent_ram_zone *prz)
144 { 144 {
145 struct persistent_ram_buffer *buffer = prz->buffer; 145 struct persistent_ram_buffer *buffer = prz->buffer;
146 uint8_t *block; 146 uint8_t *block;
147 uint8_t *par; 147 uint8_t *par;
148 148
149 if (!prz->ecc_info.ecc_size) 149 if (!prz->ecc_info.ecc_size)
150 return; 150 return;
151 151
152 block = buffer->data; 152 block = buffer->data;
153 par = prz->par_buffer; 153 par = prz->par_buffer;
154 while (block < buffer->data + buffer_size(prz)) { 154 while (block < buffer->data + buffer_size(prz)) {
155 int numerr; 155 int numerr;
156 int size = prz->ecc_info.block_size; 156 int size = prz->ecc_info.block_size;
157 if (block + size > buffer->data + prz->buffer_size) 157 if (block + size > buffer->data + prz->buffer_size)
158 size = buffer->data + prz->buffer_size - block; 158 size = buffer->data + prz->buffer_size - block;
159 numerr = persistent_ram_decode_rs8(prz, block, size, par); 159 numerr = persistent_ram_decode_rs8(prz, block, size, par);
160 if (numerr > 0) { 160 if (numerr > 0) {
161 pr_devel("persistent_ram: error in block %p, %d\n", 161 pr_devel("persistent_ram: error in block %p, %d\n",
162 block, numerr); 162 block, numerr);
163 prz->corrected_bytes += numerr; 163 prz->corrected_bytes += numerr;
164 } else if (numerr < 0) { 164 } else if (numerr < 0) {
165 pr_devel("persistent_ram: uncorrectable error in block %p\n", 165 pr_devel("persistent_ram: uncorrectable error in block %p\n",
166 block); 166 block);
167 prz->bad_blocks++; 167 prz->bad_blocks++;
168 } 168 }
169 block += prz->ecc_info.block_size; 169 block += prz->ecc_info.block_size;
170 par += prz->ecc_info.ecc_size; 170 par += prz->ecc_info.ecc_size;
171 } 171 }
172 } 172 }
173 173
174 static int persistent_ram_init_ecc(struct persistent_ram_zone *prz, 174 static int persistent_ram_init_ecc(struct persistent_ram_zone *prz,
175 struct persistent_ram_ecc_info *ecc_info) 175 struct persistent_ram_ecc_info *ecc_info)
176 { 176 {
177 int numerr; 177 int numerr;
178 struct persistent_ram_buffer *buffer = prz->buffer; 178 struct persistent_ram_buffer *buffer = prz->buffer;
179 int ecc_blocks; 179 int ecc_blocks;
180 size_t ecc_total; 180 size_t ecc_total;
181 181
182 if (!ecc_info || !ecc_info->ecc_size) 182 if (!ecc_info || !ecc_info->ecc_size)
183 return 0; 183 return 0;
184 184
185 prz->ecc_info.block_size = ecc_info->block_size ?: 128; 185 prz->ecc_info.block_size = ecc_info->block_size ?: 128;
186 prz->ecc_info.ecc_size = ecc_info->ecc_size ?: 16; 186 prz->ecc_info.ecc_size = ecc_info->ecc_size ?: 16;
187 prz->ecc_info.symsize = ecc_info->symsize ?: 8; 187 prz->ecc_info.symsize = ecc_info->symsize ?: 8;
188 prz->ecc_info.poly = ecc_info->poly ?: 0x11d; 188 prz->ecc_info.poly = ecc_info->poly ?: 0x11d;
189 189
190 ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_info.ecc_size, 190 ecc_blocks = DIV_ROUND_UP(prz->buffer_size - prz->ecc_info.ecc_size,
191 prz->ecc_info.block_size + 191 prz->ecc_info.block_size +
192 prz->ecc_info.ecc_size); 192 prz->ecc_info.ecc_size);
193 ecc_total = (ecc_blocks + 1) * prz->ecc_info.ecc_size; 193 ecc_total = (ecc_blocks + 1) * prz->ecc_info.ecc_size;
194 if (ecc_total >= prz->buffer_size) { 194 if (ecc_total >= prz->buffer_size) {
195 pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n", 195 pr_err("%s: invalid ecc_size %u (total %zu, buffer size %zu)\n",
196 __func__, prz->ecc_info.ecc_size, 196 __func__, prz->ecc_info.ecc_size,
197 ecc_total, prz->buffer_size); 197 ecc_total, prz->buffer_size);
198 return -EINVAL; 198 return -EINVAL;
199 } 199 }
200 200
201 prz->buffer_size -= ecc_total; 201 prz->buffer_size -= ecc_total;
202 prz->par_buffer = buffer->data + prz->buffer_size; 202 prz->par_buffer = buffer->data + prz->buffer_size;
203 prz->par_header = prz->par_buffer + 203 prz->par_header = prz->par_buffer +
204 ecc_blocks * prz->ecc_info.ecc_size; 204 ecc_blocks * prz->ecc_info.ecc_size;
205 205
206 /* 206 /*
207 * first consecutive root is 0 207 * first consecutive root is 0
208 * primitive element to generate roots = 1 208 * primitive element to generate roots = 1
209 */ 209 */
210 prz->rs_decoder = init_rs(prz->ecc_info.symsize, prz->ecc_info.poly, 210 prz->rs_decoder = init_rs(prz->ecc_info.symsize, prz->ecc_info.poly,
211 0, 1, prz->ecc_info.ecc_size); 211 0, 1, prz->ecc_info.ecc_size);
212 if (prz->rs_decoder == NULL) { 212 if (prz->rs_decoder == NULL) {
213 pr_info("persistent_ram: init_rs failed\n"); 213 pr_info("persistent_ram: init_rs failed\n");
214 return -EINVAL; 214 return -EINVAL;
215 } 215 }
216 216
217 prz->corrected_bytes = 0; 217 prz->corrected_bytes = 0;
218 prz->bad_blocks = 0; 218 prz->bad_blocks = 0;
219 219
220 numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer), 220 numerr = persistent_ram_decode_rs8(prz, buffer, sizeof(*buffer),
221 prz->par_header); 221 prz->par_header);
222 if (numerr > 0) { 222 if (numerr > 0) {
223 pr_info("persistent_ram: error in header, %d\n", numerr); 223 pr_info("persistent_ram: error in header, %d\n", numerr);
224 prz->corrected_bytes += numerr; 224 prz->corrected_bytes += numerr;
225 } else if (numerr < 0) { 225 } else if (numerr < 0) {
226 pr_info("persistent_ram: uncorrectable error in header\n"); 226 pr_info("persistent_ram: uncorrectable error in header\n");
227 prz->bad_blocks++; 227 prz->bad_blocks++;
228 } 228 }
229 229
230 return 0; 230 return 0;
231 } 231 }
232 232
233 ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz, 233 ssize_t persistent_ram_ecc_string(struct persistent_ram_zone *prz,
234 char *str, size_t len) 234 char *str, size_t len)
235 { 235 {
236 ssize_t ret; 236 ssize_t ret;
237 237
238 if (!prz->ecc_info.ecc_size)
239 return 0;
240
238 if (prz->corrected_bytes || prz->bad_blocks) 241 if (prz->corrected_bytes || prz->bad_blocks)
239 ret = snprintf(str, len, "" 242 ret = snprintf(str, len, ""
240 "\n%d Corrected bytes, %d unrecoverable blocks\n", 243 "\n%d Corrected bytes, %d unrecoverable blocks\n",
241 prz->corrected_bytes, prz->bad_blocks); 244 prz->corrected_bytes, prz->bad_blocks);
242 else 245 else
243 ret = snprintf(str, len, "\nNo errors detected\n"); 246 ret = snprintf(str, len, "\nNo errors detected\n");
244 247
245 return ret; 248 return ret;
246 } 249 }
247 250
248 static void notrace persistent_ram_update(struct persistent_ram_zone *prz, 251 static void notrace persistent_ram_update(struct persistent_ram_zone *prz,
249 const void *s, unsigned int start, unsigned int count) 252 const void *s, unsigned int start, unsigned int count)
250 { 253 {
251 struct persistent_ram_buffer *buffer = prz->buffer; 254 struct persistent_ram_buffer *buffer = prz->buffer;
252 memcpy(buffer->data + start, s, count); 255 memcpy(buffer->data + start, s, count);
253 persistent_ram_update_ecc(prz, start, count); 256 persistent_ram_update_ecc(prz, start, count);
254 } 257 }
255 258
256 void persistent_ram_save_old(struct persistent_ram_zone *prz) 259 void persistent_ram_save_old(struct persistent_ram_zone *prz)
257 { 260 {
258 struct persistent_ram_buffer *buffer = prz->buffer; 261 struct persistent_ram_buffer *buffer = prz->buffer;
259 size_t size = buffer_size(prz); 262 size_t size = buffer_size(prz);
260 size_t start = buffer_start(prz); 263 size_t start = buffer_start(prz);
261 264
262 if (!size) 265 if (!size)
263 return; 266 return;
264 267
265 if (!prz->old_log) { 268 if (!prz->old_log) {
266 persistent_ram_ecc_old(prz); 269 persistent_ram_ecc_old(prz);
267 prz->old_log = kmalloc(size, GFP_KERNEL); 270 prz->old_log = kmalloc(size, GFP_KERNEL);
268 } 271 }
269 if (!prz->old_log) { 272 if (!prz->old_log) {
270 pr_err("persistent_ram: failed to allocate buffer\n"); 273 pr_err("persistent_ram: failed to allocate buffer\n");
271 return; 274 return;
272 } 275 }
273 276
274 prz->old_log_size = size; 277 prz->old_log_size = size;
275 memcpy(prz->old_log, &buffer->data[start], size - start); 278 memcpy(prz->old_log, &buffer->data[start], size - start);
276 memcpy(prz->old_log + size - start, &buffer->data[0], start); 279 memcpy(prz->old_log + size - start, &buffer->data[0], start);
277 } 280 }
278 281
279 int notrace persistent_ram_write(struct persistent_ram_zone *prz, 282 int notrace persistent_ram_write(struct persistent_ram_zone *prz,
280 const void *s, unsigned int count) 283 const void *s, unsigned int count)
281 { 284 {
282 int rem; 285 int rem;
283 int c = count; 286 int c = count;
284 size_t start; 287 size_t start;
285 288
286 if (unlikely(c > prz->buffer_size)) { 289 if (unlikely(c > prz->buffer_size)) {
287 s += c - prz->buffer_size; 290 s += c - prz->buffer_size;
288 c = prz->buffer_size; 291 c = prz->buffer_size;
289 } 292 }
290 293
291 buffer_size_add(prz, c); 294 buffer_size_add(prz, c);
292 295
293 start = buffer_start_add(prz, c); 296 start = buffer_start_add(prz, c);
294 297
295 rem = prz->buffer_size - start; 298 rem = prz->buffer_size - start;
296 if (unlikely(rem < c)) { 299 if (unlikely(rem < c)) {
297 persistent_ram_update(prz, s, start, rem); 300 persistent_ram_update(prz, s, start, rem);
298 s += rem; 301 s += rem;
299 c -= rem; 302 c -= rem;
300 start = 0; 303 start = 0;
301 } 304 }
302 persistent_ram_update(prz, s, start, c); 305 persistent_ram_update(prz, s, start, c);
303 306
304 persistent_ram_update_header_ecc(prz); 307 persistent_ram_update_header_ecc(prz);
305 308
306 return count; 309 return count;
307 } 310 }
308 311
309 size_t persistent_ram_old_size(struct persistent_ram_zone *prz) 312 size_t persistent_ram_old_size(struct persistent_ram_zone *prz)
310 { 313 {
311 return prz->old_log_size; 314 return prz->old_log_size;
312 } 315 }
313 316
314 void *persistent_ram_old(struct persistent_ram_zone *prz) 317 void *persistent_ram_old(struct persistent_ram_zone *prz)
315 { 318 {
316 return prz->old_log; 319 return prz->old_log;
317 } 320 }
318 321
319 void persistent_ram_free_old(struct persistent_ram_zone *prz) 322 void persistent_ram_free_old(struct persistent_ram_zone *prz)
320 { 323 {
321 kfree(prz->old_log); 324 kfree(prz->old_log);
322 prz->old_log = NULL; 325 prz->old_log = NULL;
323 prz->old_log_size = 0; 326 prz->old_log_size = 0;
324 } 327 }
325 328
326 void persistent_ram_zap(struct persistent_ram_zone *prz) 329 void persistent_ram_zap(struct persistent_ram_zone *prz)
327 { 330 {
328 atomic_set(&prz->buffer->start, 0); 331 atomic_set(&prz->buffer->start, 0);
329 atomic_set(&prz->buffer->size, 0); 332 atomic_set(&prz->buffer->size, 0);
330 persistent_ram_update_header_ecc(prz); 333 persistent_ram_update_header_ecc(prz);
331 } 334 }
332 335
333 static void *persistent_ram_vmap(phys_addr_t start, size_t size) 336 static void *persistent_ram_vmap(phys_addr_t start, size_t size)
334 { 337 {
335 struct page **pages; 338 struct page **pages;
336 phys_addr_t page_start; 339 phys_addr_t page_start;
337 unsigned int page_count; 340 unsigned int page_count;
338 pgprot_t prot; 341 pgprot_t prot;
339 unsigned int i; 342 unsigned int i;
340 void *vaddr; 343 void *vaddr;
341 344
342 page_start = start - offset_in_page(start); 345 page_start = start - offset_in_page(start);
343 page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE); 346 page_count = DIV_ROUND_UP(size + offset_in_page(start), PAGE_SIZE);
344 347
345 prot = pgprot_noncached(PAGE_KERNEL); 348 prot = pgprot_noncached(PAGE_KERNEL);
346 349
347 pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL); 350 pages = kmalloc(sizeof(struct page *) * page_count, GFP_KERNEL);
348 if (!pages) { 351 if (!pages) {
349 pr_err("%s: Failed to allocate array for %u pages\n", __func__, 352 pr_err("%s: Failed to allocate array for %u pages\n", __func__,
350 page_count); 353 page_count);
351 return NULL; 354 return NULL;
352 } 355 }
353 356
354 for (i = 0; i < page_count; i++) { 357 for (i = 0; i < page_count; i++) {
355 phys_addr_t addr = page_start + i * PAGE_SIZE; 358 phys_addr_t addr = page_start + i * PAGE_SIZE;
356 pages[i] = pfn_to_page(addr >> PAGE_SHIFT); 359 pages[i] = pfn_to_page(addr >> PAGE_SHIFT);
357 } 360 }
358 vaddr = vmap(pages, page_count, VM_MAP, prot); 361 vaddr = vmap(pages, page_count, VM_MAP, prot);
359 kfree(pages); 362 kfree(pages);
360 363
361 return vaddr; 364 return vaddr;
362 } 365 }
363 366
364 static void *persistent_ram_iomap(phys_addr_t start, size_t size) 367 static void *persistent_ram_iomap(phys_addr_t start, size_t size)
365 { 368 {
366 if (!request_mem_region(start, size, "persistent_ram")) { 369 if (!request_mem_region(start, size, "persistent_ram")) {
367 pr_err("request mem region (0x%llx@0x%llx) failed\n", 370 pr_err("request mem region (0x%llx@0x%llx) failed\n",
368 (unsigned long long)size, (unsigned long long)start); 371 (unsigned long long)size, (unsigned long long)start);
369 return NULL; 372 return NULL;
370 } 373 }
371 374
372 return ioremap(start, size); 375 return ioremap(start, size);
373 } 376 }
374 377
375 static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size, 378 static int persistent_ram_buffer_map(phys_addr_t start, phys_addr_t size,
376 struct persistent_ram_zone *prz) 379 struct persistent_ram_zone *prz)
377 { 380 {
378 prz->paddr = start; 381 prz->paddr = start;
379 prz->size = size; 382 prz->size = size;
380 383
381 if (pfn_valid(start >> PAGE_SHIFT)) 384 if (pfn_valid(start >> PAGE_SHIFT))
382 prz->vaddr = persistent_ram_vmap(start, size); 385 prz->vaddr = persistent_ram_vmap(start, size);
383 else 386 else
384 prz->vaddr = persistent_ram_iomap(start, size); 387 prz->vaddr = persistent_ram_iomap(start, size);
385 388
386 if (!prz->vaddr) { 389 if (!prz->vaddr) {
387 pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__, 390 pr_err("%s: Failed to map 0x%llx pages at 0x%llx\n", __func__,
388 (unsigned long long)size, (unsigned long long)start); 391 (unsigned long long)size, (unsigned long long)start);
389 return -ENOMEM; 392 return -ENOMEM;
390 } 393 }
391 394
392 prz->buffer = prz->vaddr + offset_in_page(start); 395 prz->buffer = prz->vaddr + offset_in_page(start);
393 prz->buffer_size = size - sizeof(struct persistent_ram_buffer); 396 prz->buffer_size = size - sizeof(struct persistent_ram_buffer);
394 397
395 return 0; 398 return 0;
396 } 399 }
397 400
398 static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig, 401 static int persistent_ram_post_init(struct persistent_ram_zone *prz, u32 sig,
399 struct persistent_ram_ecc_info *ecc_info) 402 struct persistent_ram_ecc_info *ecc_info)
400 { 403 {
401 int ret; 404 int ret;
402 405
403 ret = persistent_ram_init_ecc(prz, ecc_info); 406 ret = persistent_ram_init_ecc(prz, ecc_info);
404 if (ret) 407 if (ret)
405 return ret; 408 return ret;
406 409
407 sig ^= PERSISTENT_RAM_SIG; 410 sig ^= PERSISTENT_RAM_SIG;
408 411
409 if (prz->buffer->sig == sig) { 412 if (prz->buffer->sig == sig) {
410 if (buffer_size(prz) > prz->buffer_size || 413 if (buffer_size(prz) > prz->buffer_size ||
411 buffer_start(prz) > buffer_size(prz)) 414 buffer_start(prz) > buffer_size(prz))
412 pr_info("persistent_ram: found existing invalid buffer," 415 pr_info("persistent_ram: found existing invalid buffer,"
413 " size %zu, start %zu\n", 416 " size %zu, start %zu\n",
414 buffer_size(prz), buffer_start(prz)); 417 buffer_size(prz), buffer_start(prz));
415 else { 418 else {
416 pr_debug("persistent_ram: found existing buffer," 419 pr_debug("persistent_ram: found existing buffer,"
417 " size %zu, start %zu\n", 420 " size %zu, start %zu\n",
418 buffer_size(prz), buffer_start(prz)); 421 buffer_size(prz), buffer_start(prz));
419 persistent_ram_save_old(prz); 422 persistent_ram_save_old(prz);
420 return 0; 423 return 0;
421 } 424 }
422 } else { 425 } else {
423 pr_debug("persistent_ram: no valid data in buffer" 426 pr_debug("persistent_ram: no valid data in buffer"
424 " (sig = 0x%08x)\n", prz->buffer->sig); 427 " (sig = 0x%08x)\n", prz->buffer->sig);
425 } 428 }
426 429
427 prz->buffer->sig = sig; 430 prz->buffer->sig = sig;
428 persistent_ram_zap(prz); 431 persistent_ram_zap(prz);
429 432
430 return 0; 433 return 0;
431 } 434 }
432 435
433 void persistent_ram_free(struct persistent_ram_zone *prz) 436 void persistent_ram_free(struct persistent_ram_zone *prz)
434 { 437 {
435 if (!prz) 438 if (!prz)
436 return; 439 return;
437 440
438 if (prz->vaddr) { 441 if (prz->vaddr) {
439 if (pfn_valid(prz->paddr >> PAGE_SHIFT)) { 442 if (pfn_valid(prz->paddr >> PAGE_SHIFT)) {
440 vunmap(prz->vaddr); 443 vunmap(prz->vaddr);
441 } else { 444 } else {
442 iounmap(prz->vaddr); 445 iounmap(prz->vaddr);
443 release_mem_region(prz->paddr, prz->size); 446 release_mem_region(prz->paddr, prz->size);
444 } 447 }
445 prz->vaddr = NULL; 448 prz->vaddr = NULL;
446 } 449 }
447 persistent_ram_free_old(prz); 450 persistent_ram_free_old(prz);
448 kfree(prz); 451 kfree(prz);
449 } 452 }
450 453
451 struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size, 454 struct persistent_ram_zone *persistent_ram_new(phys_addr_t start, size_t size,
452 u32 sig, struct persistent_ram_ecc_info *ecc_info) 455 u32 sig, struct persistent_ram_ecc_info *ecc_info)
453 { 456 {
454 struct persistent_ram_zone *prz; 457 struct persistent_ram_zone *prz;
455 int ret = -ENOMEM; 458 int ret = -ENOMEM;
456 459
457 prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL); 460 prz = kzalloc(sizeof(struct persistent_ram_zone), GFP_KERNEL);
458 if (!prz) { 461 if (!prz) {
459 pr_err("persistent_ram: failed to allocate persistent ram zone\n"); 462 pr_err("persistent_ram: failed to allocate persistent ram zone\n");
460 goto err; 463 goto err;
461 } 464 }
462 465
463 ret = persistent_ram_buffer_map(start, size, prz); 466 ret = persistent_ram_buffer_map(start, size, prz);
464 if (ret) 467 if (ret)
465 goto err; 468 goto err;
466 469
467 ret = persistent_ram_post_init(prz, sig, ecc_info); 470 ret = persistent_ram_post_init(prz, sig, ecc_info);
468 if (ret) 471 if (ret)
469 goto err; 472 goto err;
470 473
471 return prz; 474 return prz;
472 err: 475 err:
473 persistent_ram_free(prz); 476 persistent_ram_free(prz);
474 return ERR_PTR(ret); 477 return ERR_PTR(ret);
475 } 478 }
476 479