aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-08 22:36:38 -0500
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-12-08 22:36:38 -0500
commitf4b98415953dcf85bac4ea0a2264a3ead4a7bcc4 (patch)
tree7195ababc3542402a794036b98d480b81a147c0f /arch/powerpc
parent46f5221049bb46b0188aad6b6dfab5dbc778be22 (diff)
parent6024ede9ba84aa1b891c2d6bc98eda07801235e5 (diff)
Merge branch 'nvram' into next
Diffstat (limited to 'arch/powerpc')
-rw-r--r--arch/powerpc/include/asm/nvram.h52
-rw-r--r--arch/powerpc/kernel/nvram_64.c481
-rw-r--r--arch/powerpc/mm/pgtable.c2
-rw-r--r--arch/powerpc/platforms/chrp/time.c4
-rw-r--r--arch/powerpc/platforms/pseries/nvram.c205
5 files changed, 381 insertions, 363 deletions
diff --git a/arch/powerpc/include/asm/nvram.h b/arch/powerpc/include/asm/nvram.h
index 850b72f27445..92efe67d1c57 100644
--- a/arch/powerpc/include/asm/nvram.h
+++ b/arch/powerpc/include/asm/nvram.h
@@ -10,31 +10,7 @@
10#ifndef _ASM_POWERPC_NVRAM_H 10#ifndef _ASM_POWERPC_NVRAM_H
11#define _ASM_POWERPC_NVRAM_H 11#define _ASM_POWERPC_NVRAM_H
12 12
13#include <linux/errno.h> 13/* Signatures for nvram partitions */
14
15#define NVRW_CNT 0x20
16#define NVRAM_HEADER_LEN 16 /* sizeof(struct nvram_header) */
17#define NVRAM_BLOCK_LEN 16
18#define NVRAM_MAX_REQ (2080/NVRAM_BLOCK_LEN)
19#define NVRAM_MIN_REQ (1056/NVRAM_BLOCK_LEN)
20
21#define NVRAM_AS0 0x74
22#define NVRAM_AS1 0x75
23#define NVRAM_DATA 0x77
24
25
26/* RTC Offsets */
27
28#define MOTO_RTC_SECONDS 0x1FF9
29#define MOTO_RTC_MINUTES 0x1FFA
30#define MOTO_RTC_HOURS 0x1FFB
31#define MOTO_RTC_DAY_OF_WEEK 0x1FFC
32#define MOTO_RTC_DAY_OF_MONTH 0x1FFD
33#define MOTO_RTC_MONTH 0x1FFE
34#define MOTO_RTC_YEAR 0x1FFF
35#define MOTO_RTC_CONTROLA 0x1FF8
36#define MOTO_RTC_CONTROLB 0x1FF9
37
38#define NVRAM_SIG_SP 0x02 /* support processor */ 14#define NVRAM_SIG_SP 0x02 /* support processor */
39#define NVRAM_SIG_OF 0x50 /* open firmware config */ 15#define NVRAM_SIG_OF 0x50 /* open firmware config */
40#define NVRAM_SIG_FW 0x51 /* general firmware */ 16#define NVRAM_SIG_FW 0x51 /* general firmware */
@@ -49,32 +25,19 @@
49#define NVRAM_SIG_OS 0xa0 /* OS defined */ 25#define NVRAM_SIG_OS 0xa0 /* OS defined */
50#define NVRAM_SIG_PANIC 0xa1 /* Apple OSX "panic" */ 26#define NVRAM_SIG_PANIC 0xa1 /* Apple OSX "panic" */
51 27
52/* If change this size, then change the size of NVNAME_LEN */
53struct nvram_header {
54 unsigned char signature;
55 unsigned char checksum;
56 unsigned short length;
57 char name[12];
58};
59
60#ifdef __KERNEL__ 28#ifdef __KERNEL__
61 29
30#include <linux/errno.h>
62#include <linux/list.h> 31#include <linux/list.h>
63 32
64struct nvram_partition { 33#ifdef CONFIG_PPC_PSERIES
65 struct list_head partition;
66 struct nvram_header header;
67 unsigned int index;
68};
69
70
71extern int nvram_write_error_log(char * buff, int length, 34extern int nvram_write_error_log(char * buff, int length,
72 unsigned int err_type, unsigned int err_seq); 35 unsigned int err_type, unsigned int err_seq);
73extern int nvram_read_error_log(char * buff, int length, 36extern int nvram_read_error_log(char * buff, int length,
74 unsigned int * err_type, unsigned int *err_seq); 37 unsigned int * err_type, unsigned int *err_seq);
75extern int nvram_clear_error_log(void); 38extern int nvram_clear_error_log(void);
76
77extern int pSeries_nvram_init(void); 39extern int pSeries_nvram_init(void);
40#endif /* CONFIG_PPC_PSERIES */
78 41
79#ifdef CONFIG_MMIO_NVRAM 42#ifdef CONFIG_MMIO_NVRAM
80extern int mmio_nvram_init(void); 43extern int mmio_nvram_init(void);
@@ -85,6 +48,13 @@ static inline int mmio_nvram_init(void)
85} 48}
86#endif 49#endif
87 50
51extern int __init nvram_scan_partitions(void);
52extern loff_t nvram_create_partition(const char *name, int sig,
53 int req_size, int min_size);
54extern int nvram_remove_partition(const char *name, int sig);
55extern int nvram_get_partition_size(loff_t data_index);
56extern loff_t nvram_find_partition(const char *name, int sig, int *out_size);
57
88#endif /* __KERNEL__ */ 58#endif /* __KERNEL__ */
89 59
90/* PowerMac specific nvram stuffs */ 60/* PowerMac specific nvram stuffs */
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c
index 9cf197f01e94..bb12b3248f13 100644
--- a/arch/powerpc/kernel/nvram_64.c
+++ b/arch/powerpc/kernel/nvram_64.c
@@ -34,15 +34,26 @@
34 34
35#undef DEBUG_NVRAM 35#undef DEBUG_NVRAM
36 36
37static struct nvram_partition * nvram_part; 37#define NVRAM_HEADER_LEN sizeof(struct nvram_header)
38static long nvram_error_log_index = -1; 38#define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN
39static long nvram_error_log_size = 0; 39
40/* If change this size, then change the size of NVNAME_LEN */
41struct nvram_header {
42 unsigned char signature;
43 unsigned char checksum;
44 unsigned short length;
45 /* Terminating null required only for names < 12 chars. */
46 char name[12];
47};
40 48
41struct err_log_info { 49struct nvram_partition {
42 int error_type; 50 struct list_head partition;
43 unsigned int seq_num; 51 struct nvram_header header;
52 unsigned int index;
44}; 53};
45 54
55static LIST_HEAD(nvram_partitions);
56
46static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) 57static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin)
47{ 58{
48 int size; 59 int size;
@@ -186,14 +197,12 @@ static struct miscdevice nvram_dev = {
186#ifdef DEBUG_NVRAM 197#ifdef DEBUG_NVRAM
187static void __init nvram_print_partitions(char * label) 198static void __init nvram_print_partitions(char * label)
188{ 199{
189 struct list_head * p;
190 struct nvram_partition * tmp_part; 200 struct nvram_partition * tmp_part;
191 201
192 printk(KERN_WARNING "--------%s---------\n", label); 202 printk(KERN_WARNING "--------%s---------\n", label);
193 printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n"); 203 printk(KERN_WARNING "indx\t\tsig\tchks\tlen\tname\n");
194 list_for_each(p, &nvram_part->partition) { 204 list_for_each_entry(tmp_part, &nvram_partitions, partition) {
195 tmp_part = list_entry(p, struct nvram_partition, partition); 205 printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%12s\n",
196 printk(KERN_WARNING "%4d \t%02x\t%02x\t%d\t%s\n",
197 tmp_part->index, tmp_part->header.signature, 206 tmp_part->index, tmp_part->header.signature,
198 tmp_part->header.checksum, tmp_part->header.length, 207 tmp_part->header.checksum, tmp_part->header.length,
199 tmp_part->header.name); 208 tmp_part->header.name);
@@ -228,95 +237,113 @@ static unsigned char __init nvram_checksum(struct nvram_header *p)
228 return c_sum; 237 return c_sum;
229} 238}
230 239
231static int __init nvram_remove_os_partition(void) 240/**
241 * nvram_remove_partition - Remove one or more partitions in nvram
242 * @name: name of the partition to remove, or NULL for a
243 * signature only match
244 * @sig: signature of the partition(s) to remove
245 */
246
247int __init nvram_remove_partition(const char *name, int sig)
232{ 248{
233 struct list_head *i; 249 struct nvram_partition *part, *prev, *tmp;
234 struct list_head *j;
235 struct nvram_partition * part;
236 struct nvram_partition * cur_part;
237 int rc; 250 int rc;
238 251
239 list_for_each(i, &nvram_part->partition) { 252 list_for_each_entry(part, &nvram_partitions, partition) {
240 part = list_entry(i, struct nvram_partition, partition); 253 if (part->header.signature != sig)
241 if (part->header.signature != NVRAM_SIG_OS)
242 continue; 254 continue;
243 255 if (name && strncmp(name, part->header.name, 12))
244 /* Make os partition a free partition */ 256 continue;
257
258 /* Make partition a free partition */
245 part->header.signature = NVRAM_SIG_FREE; 259 part->header.signature = NVRAM_SIG_FREE;
246 sprintf(part->header.name, "wwwwwwwwwwww"); 260 strncpy(part->header.name, "wwwwwwwwwwww", 12);
247 part->header.checksum = nvram_checksum(&part->header); 261 part->header.checksum = nvram_checksum(&part->header);
248
249 /* Merge contiguous free partitions backwards */
250 list_for_each_prev(j, &part->partition) {
251 cur_part = list_entry(j, struct nvram_partition, partition);
252 if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
253 break;
254 }
255
256 part->header.length += cur_part->header.length;
257 part->header.checksum = nvram_checksum(&part->header);
258 part->index = cur_part->index;
259
260 list_del(&cur_part->partition);
261 kfree(cur_part);
262 j = &part->partition; /* fixup our loop */
263 }
264
265 /* Merge contiguous free partitions forwards */
266 list_for_each(j, &part->partition) {
267 cur_part = list_entry(j, struct nvram_partition, partition);
268 if (cur_part == nvram_part || cur_part->header.signature != NVRAM_SIG_FREE) {
269 break;
270 }
271
272 part->header.length += cur_part->header.length;
273 part->header.checksum = nvram_checksum(&part->header);
274
275 list_del(&cur_part->partition);
276 kfree(cur_part);
277 j = &part->partition; /* fixup our loop */
278 }
279
280 rc = nvram_write_header(part); 262 rc = nvram_write_header(part);
281 if (rc <= 0) { 263 if (rc <= 0) {
282 printk(KERN_ERR "nvram_remove_os_partition: nvram_write failed (%d)\n", rc); 264 printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc);
283 return rc; 265 return rc;
284 } 266 }
267 }
285 268
269 /* Merge contiguous ones */
270 prev = NULL;
271 list_for_each_entry_safe(part, tmp, &nvram_partitions, partition) {
272 if (part->header.signature != NVRAM_SIG_FREE) {
273 prev = NULL;
274 continue;
275 }
276 if (prev) {
277 prev->header.length += part->header.length;
278 prev->header.checksum = nvram_checksum(&part->header);
279 rc = nvram_write_header(part);
280 if (rc <= 0) {
281 printk(KERN_ERR "nvram_remove_partition: nvram_write failed (%d)\n", rc);
282 return rc;
283 }
284 list_del(&part->partition);
285 kfree(part);
286 } else
287 prev = part;
286 } 288 }
287 289
288 return 0; 290 return 0;
289} 291}
290 292
291/* nvram_create_os_partition 293/**
294 * nvram_create_partition - Create a partition in nvram
295 * @name: name of the partition to create
296 * @sig: signature of the partition to create
297 * @req_size: size of data to allocate in bytes
298 * @min_size: minimum acceptable size (0 means req_size)
292 * 299 *
293 * Create a OS linux partition to buffer error logs. 300 * Returns a negative error code or a positive nvram index
294 * Will create a partition starting at the first free 301 * of the beginning of the data area of the newly created
295 * space found if space has enough room. 302 * partition. If you provided a min_size smaller than req_size
303 * you need to query for the actual size yourself after the
304 * call using nvram_partition_get_size().
296 */ 305 */
297static int __init nvram_create_os_partition(void) 306loff_t __init nvram_create_partition(const char *name, int sig,
307 int req_size, int min_size)
298{ 308{
299 struct nvram_partition *part; 309 struct nvram_partition *part;
300 struct nvram_partition *new_part; 310 struct nvram_partition *new_part;
301 struct nvram_partition *free_part = NULL; 311 struct nvram_partition *free_part = NULL;
302 int seq_init[2] = { 0, 0 }; 312 static char nv_init_vals[16];
303 loff_t tmp_index; 313 loff_t tmp_index;
304 long size = 0; 314 long size = 0;
305 int rc; 315 int rc;
306 316
317 /* Convert sizes from bytes to blocks */
318 req_size = _ALIGN_UP(req_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN;
319 min_size = _ALIGN_UP(min_size, NVRAM_BLOCK_LEN) / NVRAM_BLOCK_LEN;
320
321 /* If no minimum size specified, make it the same as the
322 * requested size
323 */
324 if (min_size == 0)
325 min_size = req_size;
326 if (min_size > req_size)
327 return -EINVAL;
328
329 /* Now add one block to each for the header */
330 req_size += 1;
331 min_size += 1;
332
307 /* Find a free partition that will give us the maximum needed size 333 /* Find a free partition that will give us the maximum needed size
308 If can't find one that will give us the minimum size needed */ 334 If can't find one that will give us the minimum size needed */
309 list_for_each_entry(part, &nvram_part->partition, partition) { 335 list_for_each_entry(part, &nvram_partitions, partition) {
310 if (part->header.signature != NVRAM_SIG_FREE) 336 if (part->header.signature != NVRAM_SIG_FREE)
311 continue; 337 continue;
312 338
313 if (part->header.length >= NVRAM_MAX_REQ) { 339 if (part->header.length >= req_size) {
314 size = NVRAM_MAX_REQ; 340 size = req_size;
315 free_part = part; 341 free_part = part;
316 break; 342 break;
317 } 343 }
318 if (!size && part->header.length >= NVRAM_MIN_REQ) { 344 if (part->header.length > size &&
319 size = NVRAM_MIN_REQ; 345 part->header.length >= min_size) {
346 size = part->header.length;
320 free_part = part; 347 free_part = part;
321 } 348 }
322 } 349 }
@@ -326,136 +353,95 @@ static int __init nvram_create_os_partition(void)
326 /* Create our OS partition */ 353 /* Create our OS partition */
327 new_part = kmalloc(sizeof(*new_part), GFP_KERNEL); 354 new_part = kmalloc(sizeof(*new_part), GFP_KERNEL);
328 if (!new_part) { 355 if (!new_part) {
329 printk(KERN_ERR "nvram_create_os_partition: kmalloc failed\n"); 356 pr_err("nvram_create_os_partition: kmalloc failed\n");
330 return -ENOMEM; 357 return -ENOMEM;
331 } 358 }
332 359
333 new_part->index = free_part->index; 360 new_part->index = free_part->index;
334 new_part->header.signature = NVRAM_SIG_OS; 361 new_part->header.signature = sig;
335 new_part->header.length = size; 362 new_part->header.length = size;
336 strcpy(new_part->header.name, "ppc64,linux"); 363 strncpy(new_part->header.name, name, 12);
337 new_part->header.checksum = nvram_checksum(&new_part->header); 364 new_part->header.checksum = nvram_checksum(&new_part->header);
338 365
339 rc = nvram_write_header(new_part); 366 rc = nvram_write_header(new_part);
340 if (rc <= 0) { 367 if (rc <= 0) {
341 printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " 368 pr_err("nvram_create_os_partition: nvram_write_header "
342 "failed (%d)\n", rc);
343 return rc;
344 }
345
346 /* make sure and initialize to zero the sequence number and the error
347 type logged */
348 tmp_index = new_part->index + NVRAM_HEADER_LEN;
349 rc = ppc_md.nvram_write((char *)&seq_init, sizeof(seq_init), &tmp_index);
350 if (rc <= 0) {
351 printk(KERN_ERR "nvram_create_os_partition: nvram_write "
352 "failed (%d)\n", rc); 369 "failed (%d)\n", rc);
353 return rc; 370 return rc;
354 } 371 }
355
356 nvram_error_log_index = new_part->index + NVRAM_HEADER_LEN;
357 nvram_error_log_size = ((part->header.length - 1) *
358 NVRAM_BLOCK_LEN) - sizeof(struct err_log_info);
359
360 list_add_tail(&new_part->partition, &free_part->partition); 372 list_add_tail(&new_part->partition, &free_part->partition);
361 373
362 if (free_part->header.length <= size) { 374 /* Adjust or remove the partition we stole the space from */
375 if (free_part->header.length > size) {
376 free_part->index += size * NVRAM_BLOCK_LEN;
377 free_part->header.length -= size;
378 free_part->header.checksum = nvram_checksum(&free_part->header);
379 rc = nvram_write_header(free_part);
380 if (rc <= 0) {
381 pr_err("nvram_create_os_partition: nvram_write_header "
382 "failed (%d)\n", rc);
383 return rc;
384 }
385 } else {
363 list_del(&free_part->partition); 386 list_del(&free_part->partition);
364 kfree(free_part); 387 kfree(free_part);
365 return 0;
366 } 388 }
367 389
368 /* Adjust the partition we stole the space from */ 390 /* Clear the new partition */
369 free_part->index += size * NVRAM_BLOCK_LEN; 391 for (tmp_index = new_part->index + NVRAM_HEADER_LEN;
370 free_part->header.length -= size; 392 tmp_index < ((size - 1) * NVRAM_BLOCK_LEN);
371 free_part->header.checksum = nvram_checksum(&free_part->header); 393 tmp_index += NVRAM_BLOCK_LEN) {
372 394 rc = ppc_md.nvram_write(nv_init_vals, NVRAM_BLOCK_LEN, &tmp_index);
373 rc = nvram_write_header(free_part); 395 if (rc <= 0) {
374 if (rc <= 0) { 396 pr_err("nvram_create_partition: nvram_write failed (%d)\n", rc);
375 printk(KERN_ERR "nvram_create_os_partition: nvram_write_header " 397 return rc;
376 "failed (%d)\n", rc); 398 }
377 return rc;
378 } 399 }
379 400
380 return 0; 401 return new_part->index + NVRAM_HEADER_LEN;
381} 402}
382 403
383 404/**
384/* nvram_setup_partition 405 * nvram_get_partition_size - Get the data size of an nvram partition
385 * 406 * @data_index: This is the offset of the start of the data of
386 * This will setup the partition we need for buffering the 407 * the partition. The same value that is returned by
387 * error logs and cleanup partitions if needed. 408 * nvram_create_partition().
388 *
389 * The general strategy is the following:
390 * 1.) If there is ppc64,linux partition large enough then use it.
391 * 2.) If there is not a ppc64,linux partition large enough, search
392 * for a free partition that is large enough.
393 * 3.) If there is not a free partition large enough remove
394 * _all_ OS partitions and consolidate the space.
395 * 4.) Will first try getting a chunk that will satisfy the maximum
396 * error log size (NVRAM_MAX_REQ).
397 * 5.) If the max chunk cannot be allocated then try finding a chunk
398 * that will satisfy the minum needed (NVRAM_MIN_REQ).
399 */ 409 */
400static int __init nvram_setup_partition(void) 410int nvram_get_partition_size(loff_t data_index)
401{ 411{
402 struct list_head * p; 412 struct nvram_partition *part;
403 struct nvram_partition * part; 413
404 int rc; 414 list_for_each_entry(part, &nvram_partitions, partition) {
405 415 if (part->index + NVRAM_HEADER_LEN == data_index)
406 /* For now, we don't do any of this on pmac, until I 416 return (part->header.length - 1) * NVRAM_BLOCK_LEN;
407 * have figured out if it's worth killing some unused stuffs 417 }
408 * in our nvram, as Apple defined partitions use pretty much 418 return -1;
409 * all of the space 419}
410 */
411 if (machine_is(powermac))
412 return -ENOSPC;
413
414 /* see if we have an OS partition that meets our needs.
415 will try getting the max we need. If not we'll delete
416 partitions and try again. */
417 list_for_each(p, &nvram_part->partition) {
418 part = list_entry(p, struct nvram_partition, partition);
419 if (part->header.signature != NVRAM_SIG_OS)
420 continue;
421 420
422 if (strcmp(part->header.name, "ppc64,linux"))
423 continue;
424 421
425 if (part->header.length >= NVRAM_MIN_REQ) { 422/**
426 /* found our partition */ 423 * nvram_find_partition - Find an nvram partition by signature and name
427 nvram_error_log_index = part->index + NVRAM_HEADER_LEN; 424 * @name: Name of the partition or NULL for any name
428 nvram_error_log_size = ((part->header.length - 1) * 425 * @sig: Signature to test against
429 NVRAM_BLOCK_LEN) - sizeof(struct err_log_info); 426 * @out_size: if non-NULL, returns the size of the data part of the partition
430 return 0; 427 */
428loff_t nvram_find_partition(const char *name, int sig, int *out_size)
429{
430 struct nvram_partition *p;
431
432 list_for_each_entry(p, &nvram_partitions, partition) {
433 if (p->header.signature == sig &&
434 (!name || !strncmp(p->header.name, name, 12))) {
435 if (out_size)
436 *out_size = (p->header.length - 1) *
437 NVRAM_BLOCK_LEN;
438 return p->index + NVRAM_HEADER_LEN;
431 } 439 }
432 } 440 }
433
434 /* try creating a partition with the free space we have */
435 rc = nvram_create_os_partition();
436 if (!rc) {
437 return 0;
438 }
439
440 /* need to free up some space */
441 rc = nvram_remove_os_partition();
442 if (rc) {
443 return rc;
444 }
445
446 /* create a partition in this new space */
447 rc = nvram_create_os_partition();
448 if (rc) {
449 printk(KERN_ERR "nvram_create_os_partition: Could not find a "
450 "NVRAM partition large enough\n");
451 return rc;
452 }
453
454 return 0; 441 return 0;
455} 442}
456 443
457 444int __init nvram_scan_partitions(void)
458static int __init nvram_scan_partitions(void)
459{ 445{
460 loff_t cur_index = 0; 446 loff_t cur_index = 0;
461 struct nvram_header phead; 447 struct nvram_header phead;
@@ -465,7 +451,7 @@ static int __init nvram_scan_partitions(void)
465 int total_size; 451 int total_size;
466 int err; 452 int err;
467 453
468 if (ppc_md.nvram_size == NULL) 454 if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
469 return -ENODEV; 455 return -ENODEV;
470 total_size = ppc_md.nvram_size(); 456 total_size = ppc_md.nvram_size();
471 457
@@ -512,12 +498,16 @@ static int __init nvram_scan_partitions(void)
512 498
513 memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN); 499 memcpy(&tmp_part->header, &phead, NVRAM_HEADER_LEN);
514 tmp_part->index = cur_index; 500 tmp_part->index = cur_index;
515 list_add_tail(&tmp_part->partition, &nvram_part->partition); 501 list_add_tail(&tmp_part->partition, &nvram_partitions);
516 502
517 cur_index += phead.length * NVRAM_BLOCK_LEN; 503 cur_index += phead.length * NVRAM_BLOCK_LEN;
518 } 504 }
519 err = 0; 505 err = 0;
520 506
507#ifdef DEBUG_NVRAM
508 nvram_print_partitions("NVRAM Partitions");
509#endif
510
521 out: 511 out:
522 kfree(header); 512 kfree(header);
523 return err; 513 return err;
@@ -525,9 +515,10 @@ static int __init nvram_scan_partitions(void)
525 515
526static int __init nvram_init(void) 516static int __init nvram_init(void)
527{ 517{
528 int error;
529 int rc; 518 int rc;
530 519
520 BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16);
521
531 if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) 522 if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0)
532 return -ENODEV; 523 return -ENODEV;
533 524
@@ -537,29 +528,6 @@ static int __init nvram_init(void)
537 return rc; 528 return rc;
538 } 529 }
539 530
540 /* initialize our anchor for the nvram partition list */
541 nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL);
542 if (!nvram_part) {
543 printk(KERN_ERR "nvram_init: Failed kmalloc\n");
544 return -ENOMEM;
545 }
546 INIT_LIST_HEAD(&nvram_part->partition);
547
548 /* Get all the NVRAM partitions */
549 error = nvram_scan_partitions();
550 if (error) {
551 printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n");
552 return error;
553 }
554
555 if(nvram_setup_partition())
556 printk(KERN_WARNING "nvram_init: Could not find nvram partition"
557 " for nvram buffered error logging.\n");
558
559#ifdef DEBUG_NVRAM
560 nvram_print_partitions("NVRAM Partitions");
561#endif
562
563 return rc; 531 return rc;
564} 532}
565 533
@@ -568,135 +536,6 @@ void __exit nvram_cleanup(void)
568 misc_deregister( &nvram_dev ); 536 misc_deregister( &nvram_dev );
569} 537}
570 538
571
572#ifdef CONFIG_PPC_PSERIES
573
574/* nvram_write_error_log
575 *
576 * We need to buffer the error logs into nvram to ensure that we have
577 * the failure information to decode. If we have a severe error there
578 * is no way to guarantee that the OS or the machine is in a state to
579 * get back to user land and write the error to disk. For example if
580 * the SCSI device driver causes a Machine Check by writing to a bad
581 * IO address, there is no way of guaranteeing that the device driver
582 * is in any state that is would also be able to write the error data
583 * captured to disk, thus we buffer it in NVRAM for analysis on the
584 * next boot.
585 *
586 * In NVRAM the partition containing the error log buffer will looks like:
587 * Header (in bytes):
588 * +-----------+----------+--------+------------+------------------+
589 * | signature | checksum | length | name | data |
590 * |0 |1 |2 3|4 15|16 length-1|
591 * +-----------+----------+--------+------------+------------------+
592 *
593 * The 'data' section would look like (in bytes):
594 * +--------------+------------+-----------------------------------+
595 * | event_logged | sequence # | error log |
596 * |0 3|4 7|8 nvram_error_log_size-1|
597 * +--------------+------------+-----------------------------------+
598 *
599 * event_logged: 0 if event has not been logged to syslog, 1 if it has
600 * sequence #: The unique sequence # for each event. (until it wraps)
601 * error log: The error log from event_scan
602 */
603int nvram_write_error_log(char * buff, int length,
604 unsigned int err_type, unsigned int error_log_cnt)
605{
606 int rc;
607 loff_t tmp_index;
608 struct err_log_info info;
609
610 if (nvram_error_log_index == -1) {
611 return -ESPIPE;
612 }
613
614 if (length > nvram_error_log_size) {
615 length = nvram_error_log_size;
616 }
617
618 info.error_type = err_type;
619 info.seq_num = error_log_cnt;
620
621 tmp_index = nvram_error_log_index;
622
623 rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
624 if (rc <= 0) {
625 printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
626 return rc;
627 }
628
629 rc = ppc_md.nvram_write(buff, length, &tmp_index);
630 if (rc <= 0) {
631 printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
632 return rc;
633 }
634
635 return 0;
636}
637
638/* nvram_read_error_log
639 *
640 * Reads nvram for error log for at most 'length'
641 */
642int nvram_read_error_log(char * buff, int length,
643 unsigned int * err_type, unsigned int * error_log_cnt)
644{
645 int rc;
646 loff_t tmp_index;
647 struct err_log_info info;
648
649 if (nvram_error_log_index == -1)
650 return -1;
651
652 if (length > nvram_error_log_size)
653 length = nvram_error_log_size;
654
655 tmp_index = nvram_error_log_index;
656
657 rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
658 if (rc <= 0) {
659 printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
660 return rc;
661 }
662
663 rc = ppc_md.nvram_read(buff, length, &tmp_index);
664 if (rc <= 0) {
665 printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
666 return rc;
667 }
668
669 *error_log_cnt = info.seq_num;
670 *err_type = info.error_type;
671
672 return 0;
673}
674
675/* This doesn't actually zero anything, but it sets the event_logged
676 * word to tell that this event is safely in syslog.
677 */
678int nvram_clear_error_log(void)
679{
680 loff_t tmp_index;
681 int clear_word = ERR_FLAG_ALREADY_LOGGED;
682 int rc;
683
684 if (nvram_error_log_index == -1)
685 return -1;
686
687 tmp_index = nvram_error_log_index;
688
689 rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
690 if (rc <= 0) {
691 printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
692 return rc;
693 }
694
695 return 0;
696}
697
698#endif /* CONFIG_PPC_PSERIES */
699
700module_init(nvram_init); 539module_init(nvram_init);
701module_exit(nvram_cleanup); 540module_exit(nvram_cleanup);
702MODULE_LICENSE("GPL"); 541MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/mm/pgtable.c b/arch/powerpc/mm/pgtable.c
index 2c7e801ab20b..6a3997f98dfb 100644
--- a/arch/powerpc/mm/pgtable.c
+++ b/arch/powerpc/mm/pgtable.c
@@ -92,7 +92,7 @@ static void pte_free_rcu_callback(struct rcu_head *head)
92 92
93static void pte_free_submit(struct pte_freelist_batch *batch) 93static void pte_free_submit(struct pte_freelist_batch *batch)
94{ 94{
95 call_rcu(&batch->rcu, pte_free_rcu_callback); 95 call_rcu_sched(&batch->rcu, pte_free_rcu_callback);
96} 96}
97 97
98void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift) 98void pgtable_free_tlb(struct mmu_gather *tlb, void *table, unsigned shift)
diff --git a/arch/powerpc/platforms/chrp/time.c b/arch/powerpc/platforms/chrp/time.c
index 054dfe5b8e77..f803f4b8ab6f 100644
--- a/arch/powerpc/platforms/chrp/time.c
+++ b/arch/powerpc/platforms/chrp/time.c
@@ -29,6 +29,10 @@
29 29
30extern spinlock_t rtc_lock; 30extern spinlock_t rtc_lock;
31 31
32#define NVRAM_AS0 0x74
33#define NVRAM_AS1 0x75
34#define NVRAM_DATA 0x77
35
32static int nvram_as1 = NVRAM_AS1; 36static int nvram_as1 = NVRAM_AS1;
33static int nvram_as0 = NVRAM_AS0; 37static int nvram_as0 = NVRAM_AS0;
34static int nvram_data = NVRAM_DATA; 38static int nvram_data = NVRAM_DATA;
diff --git a/arch/powerpc/platforms/pseries/nvram.c b/arch/powerpc/platforms/pseries/nvram.c
index bc3c7f2abd79..7e828ba29bc3 100644
--- a/arch/powerpc/platforms/pseries/nvram.c
+++ b/arch/powerpc/platforms/pseries/nvram.c
@@ -22,11 +22,25 @@
22#include <asm/prom.h> 22#include <asm/prom.h>
23#include <asm/machdep.h> 23#include <asm/machdep.h>
24 24
25/* Max bytes to read/write in one go */
26#define NVRW_CNT 0x20
27
25static unsigned int nvram_size; 28static unsigned int nvram_size;
26static int nvram_fetch, nvram_store; 29static int nvram_fetch, nvram_store;
27static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */ 30static char nvram_buf[NVRW_CNT]; /* assume this is in the first 4GB */
28static DEFINE_SPINLOCK(nvram_lock); 31static DEFINE_SPINLOCK(nvram_lock);
29 32
33static long nvram_error_log_index = -1;
34static long nvram_error_log_size = 0;
35
36struct err_log_info {
37 int error_type;
38 unsigned int seq_num;
39};
40#define NVRAM_MAX_REQ 2079
41#define NVRAM_MIN_REQ 1055
42
43#define NVRAM_LOG_PART_NAME "ibm,rtas-log"
30 44
31static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index) 45static ssize_t pSeries_nvram_read(char *buf, size_t count, loff_t *index)
32{ 46{
@@ -119,6 +133,197 @@ static ssize_t pSeries_nvram_get_size(void)
119 return nvram_size ? nvram_size : -ENODEV; 133 return nvram_size ? nvram_size : -ENODEV;
120} 134}
121 135
136
137/* nvram_write_error_log
138 *
139 * We need to buffer the error logs into nvram to ensure that we have
140 * the failure information to decode. If we have a severe error there
141 * is no way to guarantee that the OS or the machine is in a state to
142 * get back to user land and write the error to disk. For example if
143 * the SCSI device driver causes a Machine Check by writing to a bad
144 * IO address, there is no way of guaranteeing that the device driver
145 * is in any state that is would also be able to write the error data
146 * captured to disk, thus we buffer it in NVRAM for analysis on the
147 * next boot.
148 *
149 * In NVRAM the partition containing the error log buffer will looks like:
150 * Header (in bytes):
151 * +-----------+----------+--------+------------+------------------+
152 * | signature | checksum | length | name | data |
153 * |0 |1 |2 3|4 15|16 length-1|
154 * +-----------+----------+--------+------------+------------------+
155 *
156 * The 'data' section would look like (in bytes):
157 * +--------------+------------+-----------------------------------+
158 * | event_logged | sequence # | error log |
159 * |0 3|4 7|8 nvram_error_log_size-1|
160 * +--------------+------------+-----------------------------------+
161 *
162 * event_logged: 0 if event has not been logged to syslog, 1 if it has
163 * sequence #: The unique sequence # for each event. (until it wraps)
164 * error log: The error log from event_scan
165 */
166int nvram_write_error_log(char * buff, int length,
167 unsigned int err_type, unsigned int error_log_cnt)
168{
169 int rc;
170 loff_t tmp_index;
171 struct err_log_info info;
172
173 if (nvram_error_log_index == -1) {
174 return -ESPIPE;
175 }
176
177 if (length > nvram_error_log_size) {
178 length = nvram_error_log_size;
179 }
180
181 info.error_type = err_type;
182 info.seq_num = error_log_cnt;
183
184 tmp_index = nvram_error_log_index;
185
186 rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index);
187 if (rc <= 0) {
188 printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
189 return rc;
190 }
191
192 rc = ppc_md.nvram_write(buff, length, &tmp_index);
193 if (rc <= 0) {
194 printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc);
195 return rc;
196 }
197
198 return 0;
199}
200
201/* nvram_read_error_log
202 *
203 * Reads nvram for error log for at most 'length'
204 */
205int nvram_read_error_log(char * buff, int length,
206 unsigned int * err_type, unsigned int * error_log_cnt)
207{
208 int rc;
209 loff_t tmp_index;
210 struct err_log_info info;
211
212 if (nvram_error_log_index == -1)
213 return -1;
214
215 if (length > nvram_error_log_size)
216 length = nvram_error_log_size;
217
218 tmp_index = nvram_error_log_index;
219
220 rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index);
221 if (rc <= 0) {
222 printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
223 return rc;
224 }
225
226 rc = ppc_md.nvram_read(buff, length, &tmp_index);
227 if (rc <= 0) {
228 printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc);
229 return rc;
230 }
231
232 *error_log_cnt = info.seq_num;
233 *err_type = info.error_type;
234
235 return 0;
236}
237
238/* This doesn't actually zero anything, but it sets the event_logged
239 * word to tell that this event is safely in syslog.
240 */
241int nvram_clear_error_log(void)
242{
243 loff_t tmp_index;
244 int clear_word = ERR_FLAG_ALREADY_LOGGED;
245 int rc;
246
247 if (nvram_error_log_index == -1)
248 return -1;
249
250 tmp_index = nvram_error_log_index;
251
252 rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index);
253 if (rc <= 0) {
254 printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc);
255 return rc;
256 }
257
258 return 0;
259}
260
261/* pseries_nvram_init_log_partition
262 *
263 * This will setup the partition we need for buffering the
264 * error logs and cleanup partitions if needed.
265 *
266 * The general strategy is the following:
267 * 1.) If there is log partition large enough then use it.
268 * 2.) If there is none large enough, search
269 * for a free partition that is large enough.
270 * 3.) If there is not a free partition large enough remove
271 * _all_ OS partitions and consolidate the space.
272 * 4.) Will first try getting a chunk that will satisfy the maximum
273 * error log size (NVRAM_MAX_REQ).
274 * 5.) If the max chunk cannot be allocated then try finding a chunk
275 * that will satisfy the minum needed (NVRAM_MIN_REQ).
276 */
277static int __init pseries_nvram_init_log_partition(void)
278{
279 loff_t p;
280 int size;
281
282 /* Scan nvram for partitions */
283 nvram_scan_partitions();
284
285 /* Lookg for ours */
286 p = nvram_find_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS, &size);
287
288 /* Found one but too small, remove it */
289 if (p && size < NVRAM_MIN_REQ) {
290 pr_info("nvram: Found too small "NVRAM_LOG_PART_NAME" partition"
291 ",removing it...");
292 nvram_remove_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS);
293 p = 0;
294 }
295
296 /* Create one if we didn't find */
297 if (!p) {
298 p = nvram_create_partition(NVRAM_LOG_PART_NAME, NVRAM_SIG_OS,
299 NVRAM_MAX_REQ, NVRAM_MIN_REQ);
300 /* No room for it, try to get rid of any OS partition
301 * and try again
302 */
303 if (p == -ENOSPC) {
304 pr_info("nvram: No room to create "NVRAM_LOG_PART_NAME
305 " partition, deleting all OS partitions...");
306 nvram_remove_partition(NULL, NVRAM_SIG_OS);
307 p = nvram_create_partition(NVRAM_LOG_PART_NAME,
308 NVRAM_SIG_OS, NVRAM_MAX_REQ,
309 NVRAM_MIN_REQ);
310 }
311 }
312
313 if (p <= 0) {
314 pr_err("nvram: Failed to find or create "NVRAM_LOG_PART_NAME
315 " partition, err %d\n", (int)p);
316 return 0;
317 }
318
319 nvram_error_log_index = p;
320 nvram_error_log_size = nvram_get_partition_size(p) -
321 sizeof(struct err_log_info);
322
323 return 0;
324}
325machine_arch_initcall(pseries, pseries_nvram_init_log_partition);
326
122int __init pSeries_nvram_init(void) 327int __init pSeries_nvram_init(void)
123{ 328{
124 struct device_node *nvram; 329 struct device_node *nvram;