diff options
Diffstat (limited to 'arch/powerpc/kernel/nvram_64.c')
-rw-r--r-- | arch/powerpc/kernel/nvram_64.c | 254 |
1 files changed, 18 insertions, 236 deletions
diff --git a/arch/powerpc/kernel/nvram_64.c b/arch/powerpc/kernel/nvram_64.c index 76f546b9944d..125d86cf0afc 100644 --- a/arch/powerpc/kernel/nvram_64.c +++ b/arch/powerpc/kernel/nvram_64.c | |||
@@ -36,8 +36,6 @@ | |||
36 | 36 | ||
37 | #define NVRAM_HEADER_LEN sizeof(struct nvram_header) | 37 | #define NVRAM_HEADER_LEN sizeof(struct nvram_header) |
38 | #define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN | 38 | #define NVRAM_BLOCK_LEN NVRAM_HEADER_LEN |
39 | #define NVRAM_MAX_REQ 2079 | ||
40 | #define NVRAM_MIN_REQ 1055 | ||
41 | 39 | ||
42 | /* If change this size, then change the size of NVNAME_LEN */ | 40 | /* If change this size, then change the size of NVNAME_LEN */ |
43 | struct nvram_header { | 41 | struct nvram_header { |
@@ -54,13 +52,6 @@ struct nvram_partition { | |||
54 | }; | 52 | }; |
55 | 53 | ||
56 | static struct nvram_partition * nvram_part; | 54 | static struct nvram_partition * nvram_part; |
57 | static long nvram_error_log_index = -1; | ||
58 | static long nvram_error_log_size = 0; | ||
59 | |||
60 | struct err_log_info { | ||
61 | int error_type; | ||
62 | unsigned int seq_num; | ||
63 | }; | ||
64 | 55 | ||
65 | static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) | 56 | static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) |
66 | { | 57 | { |
@@ -254,7 +245,7 @@ static unsigned char __init nvram_checksum(struct nvram_header *p) | |||
254 | * @sig: signature of the partition(s) to remove | 245 | * @sig: signature of the partition(s) to remove |
255 | */ | 246 | */ |
256 | 247 | ||
257 | static int __init nvram_remove_partition(const char *name, int sig) | 248 | int __init nvram_remove_partition(const char *name, int sig) |
258 | { | 249 | { |
259 | struct nvram_partition *part, *prev, *tmp; | 250 | struct nvram_partition *part, *prev, *tmp; |
260 | int rc; | 251 | int rc; |
@@ -313,8 +304,8 @@ static int __init nvram_remove_partition(const char *name, int sig) | |||
313 | * you need to query for the actual size yourself after the | 304 | * you need to query for the actual size yourself after the |
314 | * call using nvram_partition_get_size(). | 305 | * call using nvram_partition_get_size(). |
315 | */ | 306 | */ |
316 | static loff_t __init nvram_create_partition(const char *name, int sig, | 307 | loff_t __init nvram_create_partition(const char *name, int sig, |
317 | int req_size, int min_size) | 308 | int req_size, int min_size) |
318 | { | 309 | { |
319 | struct nvram_partition *part; | 310 | struct nvram_partition *part; |
320 | struct nvram_partition *new_part; | 311 | struct nvram_partition *new_part; |
@@ -417,7 +408,7 @@ static loff_t __init nvram_create_partition(const char *name, int sig, | |||
417 | * the partition. The same value that is returned by | 408 | * the partition. The same value that is returned by |
418 | * nvram_create_partition(). | 409 | * nvram_create_partition(). |
419 | */ | 410 | */ |
420 | static int nvram_get_partition_size(loff_t data_index) | 411 | int nvram_get_partition_size(loff_t data_index) |
421 | { | 412 | { |
422 | struct nvram_partition *part; | 413 | struct nvram_partition *part; |
423 | 414 | ||
@@ -451,75 +442,7 @@ loff_t nvram_find_partition(const char *name, int sig, int *out_size) | |||
451 | return 0; | 442 | return 0; |
452 | } | 443 | } |
453 | 444 | ||
454 | /* nvram_setup_partition | 445 | int __init nvram_scan_partitions(void) |
455 | * | ||
456 | * This will setup the partition we need for buffering the | ||
457 | * error logs and cleanup partitions if needed. | ||
458 | * | ||
459 | * The general strategy is the following: | ||
460 | * 1.) If there is ppc64,linux partition large enough then use it. | ||
461 | * 2.) If there is not a ppc64,linux partition large enough, search | ||
462 | * for a free partition that is large enough. | ||
463 | * 3.) If there is not a free partition large enough remove | ||
464 | * _all_ OS partitions and consolidate the space. | ||
465 | * 4.) Will first try getting a chunk that will satisfy the maximum | ||
466 | * error log size (NVRAM_MAX_REQ). | ||
467 | * 5.) If the max chunk cannot be allocated then try finding a chunk | ||
468 | * that will satisfy the minum needed (NVRAM_MIN_REQ). | ||
469 | */ | ||
470 | static int __init nvram_setup_partition(void) | ||
471 | { | ||
472 | loff_t p; | ||
473 | int size; | ||
474 | |||
475 | /* For now, we don't do any of this on pmac, until I | ||
476 | * have figured out if it's worth killing some unused stuffs | ||
477 | * in our nvram, as Apple defined partitions use pretty much | ||
478 | * all of the space | ||
479 | */ | ||
480 | if (machine_is(powermac)) | ||
481 | return -ENOSPC; | ||
482 | |||
483 | p = nvram_find_partition("ppc64,linux", NVRAM_SIG_OS, &size); | ||
484 | |||
485 | /* Found one but too small, remove it */ | ||
486 | if (p && size < NVRAM_MIN_REQ) { | ||
487 | pr_info("nvram: Found too small ppc64,linux partition" | ||
488 | ",removing it..."); | ||
489 | nvram_remove_partition("ppc64,linux", NVRAM_SIG_OS); | ||
490 | p = 0; | ||
491 | } | ||
492 | |||
493 | /* Create one if we didn't find */ | ||
494 | if (!p) { | ||
495 | p = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, | ||
496 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); | ||
497 | /* No room for it, try to get rid of any OS partition | ||
498 | * and try again | ||
499 | */ | ||
500 | if (p == -ENOSPC) { | ||
501 | pr_info("nvram: No room to create ppc64,linux" | ||
502 | " partition, deleting all OS partitions..."); | ||
503 | nvram_remove_partition(NULL, NVRAM_SIG_OS); | ||
504 | p = nvram_create_partition("ppc64,linux", NVRAM_SIG_OS, | ||
505 | NVRAM_MAX_REQ, NVRAM_MIN_REQ); | ||
506 | } | ||
507 | } | ||
508 | |||
509 | if (p <= 0) { | ||
510 | pr_err("nvram: Failed to find or create ppc64,linux" | ||
511 | " partition, err %d\n", (int)p); | ||
512 | return 0; | ||
513 | } | ||
514 | |||
515 | nvram_error_log_index = p; | ||
516 | nvram_error_log_size = nvram_get_partition_size(p) - | ||
517 | sizeof(struct err_log_info); | ||
518 | |||
519 | return 0; | ||
520 | } | ||
521 | |||
522 | static int __init nvram_scan_partitions(void) | ||
523 | { | 446 | { |
524 | loff_t cur_index = 0; | 447 | loff_t cur_index = 0; |
525 | struct nvram_header phead; | 448 | struct nvram_header phead; |
@@ -529,7 +452,15 @@ static int __init nvram_scan_partitions(void) | |||
529 | int total_size; | 452 | int total_size; |
530 | int err; | 453 | int err; |
531 | 454 | ||
532 | if (ppc_md.nvram_size == NULL) | 455 | /* Initialize our anchor for the nvram partition list */ |
456 | nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); | ||
457 | if (!nvram_part) { | ||
458 | printk(KERN_ERR "nvram_init: Failed kmalloc\n"); | ||
459 | return -ENOMEM; | ||
460 | } | ||
461 | INIT_LIST_HEAD(&nvram_part->partition); | ||
462 | |||
463 | if (ppc_md.nvram_size == NULL || ppc_md.nvram_size() <= 0) | ||
533 | return -ENODEV; | 464 | return -ENODEV; |
534 | total_size = ppc_md.nvram_size(); | 465 | total_size = ppc_md.nvram_size(); |
535 | 466 | ||
@@ -582,6 +513,10 @@ static int __init nvram_scan_partitions(void) | |||
582 | } | 513 | } |
583 | err = 0; | 514 | err = 0; |
584 | 515 | ||
516 | #ifdef DEBUG_NVRAM | ||
517 | nvram_print_partitions("NVRAM Partitions"); | ||
518 | #endif | ||
519 | |||
585 | out: | 520 | out: |
586 | kfree(header); | 521 | kfree(header); |
587 | return err; | 522 | return err; |
@@ -589,7 +524,6 @@ static int __init nvram_scan_partitions(void) | |||
589 | 524 | ||
590 | static int __init nvram_init(void) | 525 | static int __init nvram_init(void) |
591 | { | 526 | { |
592 | int error; | ||
593 | int rc; | 527 | int rc; |
594 | 528 | ||
595 | BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16); | 529 | BUILD_BUG_ON(NVRAM_BLOCK_LEN != 16); |
@@ -603,29 +537,6 @@ static int __init nvram_init(void) | |||
603 | return rc; | 537 | return rc; |
604 | } | 538 | } |
605 | 539 | ||
606 | /* initialize our anchor for the nvram partition list */ | ||
607 | nvram_part = kmalloc(sizeof(struct nvram_partition), GFP_KERNEL); | ||
608 | if (!nvram_part) { | ||
609 | printk(KERN_ERR "nvram_init: Failed kmalloc\n"); | ||
610 | return -ENOMEM; | ||
611 | } | ||
612 | INIT_LIST_HEAD(&nvram_part->partition); | ||
613 | |||
614 | /* Get all the NVRAM partitions */ | ||
615 | error = nvram_scan_partitions(); | ||
616 | if (error) { | ||
617 | printk(KERN_ERR "nvram_init: Failed nvram_scan_partitions\n"); | ||
618 | return error; | ||
619 | } | ||
620 | |||
621 | if(nvram_setup_partition()) | ||
622 | printk(KERN_WARNING "nvram_init: Could not find nvram partition" | ||
623 | " for nvram buffered error logging.\n"); | ||
624 | |||
625 | #ifdef DEBUG_NVRAM | ||
626 | nvram_print_partitions("NVRAM Partitions"); | ||
627 | #endif | ||
628 | |||
629 | return rc; | 540 | return rc; |
630 | } | 541 | } |
631 | 542 | ||
@@ -634,135 +545,6 @@ void __exit nvram_cleanup(void) | |||
634 | misc_deregister( &nvram_dev ); | 545 | misc_deregister( &nvram_dev ); |
635 | } | 546 | } |
636 | 547 | ||
637 | |||
638 | #ifdef CONFIG_PPC_PSERIES | ||
639 | |||
640 | /* nvram_write_error_log | ||
641 | * | ||
642 | * We need to buffer the error logs into nvram to ensure that we have | ||
643 | * the failure information to decode. If we have a severe error there | ||
644 | * is no way to guarantee that the OS or the machine is in a state to | ||
645 | * get back to user land and write the error to disk. For example if | ||
646 | * the SCSI device driver causes a Machine Check by writing to a bad | ||
647 | * IO address, there is no way of guaranteeing that the device driver | ||
648 | * is in any state that is would also be able to write the error data | ||
649 | * captured to disk, thus we buffer it in NVRAM for analysis on the | ||
650 | * next boot. | ||
651 | * | ||
652 | * In NVRAM the partition containing the error log buffer will looks like: | ||
653 | * Header (in bytes): | ||
654 | * +-----------+----------+--------+------------+------------------+ | ||
655 | * | signature | checksum | length | name | data | | ||
656 | * |0 |1 |2 3|4 15|16 length-1| | ||
657 | * +-----------+----------+--------+------------+------------------+ | ||
658 | * | ||
659 | * The 'data' section would look like (in bytes): | ||
660 | * +--------------+------------+-----------------------------------+ | ||
661 | * | event_logged | sequence # | error log | | ||
662 | * |0 3|4 7|8 nvram_error_log_size-1| | ||
663 | * +--------------+------------+-----------------------------------+ | ||
664 | * | ||
665 | * event_logged: 0 if event has not been logged to syslog, 1 if it has | ||
666 | * sequence #: The unique sequence # for each event. (until it wraps) | ||
667 | * error log: The error log from event_scan | ||
668 | */ | ||
669 | int nvram_write_error_log(char * buff, int length, | ||
670 | unsigned int err_type, unsigned int error_log_cnt) | ||
671 | { | ||
672 | int rc; | ||
673 | loff_t tmp_index; | ||
674 | struct err_log_info info; | ||
675 | |||
676 | if (nvram_error_log_index == -1) { | ||
677 | return -ESPIPE; | ||
678 | } | ||
679 | |||
680 | if (length > nvram_error_log_size) { | ||
681 | length = nvram_error_log_size; | ||
682 | } | ||
683 | |||
684 | info.error_type = err_type; | ||
685 | info.seq_num = error_log_cnt; | ||
686 | |||
687 | tmp_index = nvram_error_log_index; | ||
688 | |||
689 | rc = ppc_md.nvram_write((char *)&info, sizeof(struct err_log_info), &tmp_index); | ||
690 | if (rc <= 0) { | ||
691 | printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | ||
692 | return rc; | ||
693 | } | ||
694 | |||
695 | rc = ppc_md.nvram_write(buff, length, &tmp_index); | ||
696 | if (rc <= 0) { | ||
697 | printk(KERN_ERR "nvram_write_error_log: Failed nvram_write (%d)\n", rc); | ||
698 | return rc; | ||
699 | } | ||
700 | |||
701 | return 0; | ||
702 | } | ||
703 | |||
704 | /* nvram_read_error_log | ||
705 | * | ||
706 | * Reads nvram for error log for at most 'length' | ||
707 | */ | ||
708 | int nvram_read_error_log(char * buff, int length, | ||
709 | unsigned int * err_type, unsigned int * error_log_cnt) | ||
710 | { | ||
711 | int rc; | ||
712 | loff_t tmp_index; | ||
713 | struct err_log_info info; | ||
714 | |||
715 | if (nvram_error_log_index == -1) | ||
716 | return -1; | ||
717 | |||
718 | if (length > nvram_error_log_size) | ||
719 | length = nvram_error_log_size; | ||
720 | |||
721 | tmp_index = nvram_error_log_index; | ||
722 | |||
723 | rc = ppc_md.nvram_read((char *)&info, sizeof(struct err_log_info), &tmp_index); | ||
724 | if (rc <= 0) { | ||
725 | printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); | ||
726 | return rc; | ||
727 | } | ||
728 | |||
729 | rc = ppc_md.nvram_read(buff, length, &tmp_index); | ||
730 | if (rc <= 0) { | ||
731 | printk(KERN_ERR "nvram_read_error_log: Failed nvram_read (%d)\n", rc); | ||
732 | return rc; | ||
733 | } | ||
734 | |||
735 | *error_log_cnt = info.seq_num; | ||
736 | *err_type = info.error_type; | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | /* This doesn't actually zero anything, but it sets the event_logged | ||
742 | * word to tell that this event is safely in syslog. | ||
743 | */ | ||
744 | int nvram_clear_error_log(void) | ||
745 | { | ||
746 | loff_t tmp_index; | ||
747 | int clear_word = ERR_FLAG_ALREADY_LOGGED; | ||
748 | int rc; | ||
749 | |||
750 | if (nvram_error_log_index == -1) | ||
751 | return -1; | ||
752 | |||
753 | tmp_index = nvram_error_log_index; | ||
754 | |||
755 | rc = ppc_md.nvram_write((char *)&clear_word, sizeof(int), &tmp_index); | ||
756 | if (rc <= 0) { | ||
757 | printk(KERN_ERR "nvram_clear_error_log: Failed nvram_write (%d)\n", rc); | ||
758 | return rc; | ||
759 | } | ||
760 | |||
761 | return 0; | ||
762 | } | ||
763 | |||
764 | #endif /* CONFIG_PPC_PSERIES */ | ||
765 | |||
766 | module_init(nvram_init); | 548 | module_init(nvram_init); |
767 | module_exit(nvram_cleanup); | 549 | module_exit(nvram_cleanup); |
768 | MODULE_LICENSE("GPL"); | 550 | MODULE_LICENSE("GPL"); |