aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/kernel')
-rw-r--r--arch/powerpc/kernel/nvram_64.c254
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 */
43struct nvram_header { 41struct nvram_header {
@@ -54,13 +52,6 @@ struct nvram_partition {
54}; 52};
55 53
56static struct nvram_partition * nvram_part; 54static struct nvram_partition * nvram_part;
57static long nvram_error_log_index = -1;
58static long nvram_error_log_size = 0;
59
60struct err_log_info {
61 int error_type;
62 unsigned int seq_num;
63};
64 55
65static loff_t dev_nvram_llseek(struct file *file, loff_t offset, int origin) 56static 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
257static int __init nvram_remove_partition(const char *name, int sig) 248int __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 */
316static loff_t __init nvram_create_partition(const char *name, int sig, 307loff_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 */
420static int nvram_get_partition_size(loff_t data_index) 411int 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 445int __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 */
470static 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
522static 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
590static int __init nvram_init(void) 525static 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 */
669int 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 */
708int 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 */
744int 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
766module_init(nvram_init); 548module_init(nvram_init);
767module_exit(nvram_cleanup); 549module_exit(nvram_cleanup);
768MODULE_LICENSE("GPL"); 550MODULE_LICENSE("GPL");