aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/kernel/nvram_64.c
diff options
context:
space:
mode:
authorBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-08-01 21:18:09 -0400
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>2010-11-29 23:37:45 -0500
commitedc79a2f3ee1c74d915f6a0ce3cb22bf468f5ad5 (patch)
treec8cfb41d324802abb501cc6503a4dcb4d8bb657b /arch/powerpc/kernel/nvram_64.c
parentd9626947f20b3dc0992e4ac28b477f7601f8f16e (diff)
powerpc/nvram: Move the log partition stuff to pseries
The nvram log partition stuff currently in nvram_64.c is really pseries specific. It isn't actually used on anything else (despite the fact that we ran the code to setup the partition on anything except powermac) and the log format is specific to pseries RTAS implementation. So move it where it belongs Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Diffstat (limited to 'arch/powerpc/kernel/nvram_64.c')
-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");