diff options
-rw-r--r-- | drivers/watchdog/hpwdt.c | 124 |
1 files changed, 69 insertions, 55 deletions
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 99aa76c489a3..850f17877e9c 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -653,7 +653,65 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) | |||
653 | dev_warn(&dev->dev, "NMI decoding is disabled. " | 653 | dev_warn(&dev->dev, "NMI decoding is disabled. " |
654 | "Your kernel does not support a NMI Watchdog.\n"); | 654 | "Your kernel does not support a NMI Watchdog.\n"); |
655 | } | 655 | } |
656 | #endif | 656 | #endif /* ARCH_HAS_NMI_WATCHDOG */ |
657 | |||
658 | static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) | ||
659 | { | ||
660 | int retval; | ||
661 | |||
662 | /* | ||
663 | * We need to map the ROM to get the CRU service. | ||
664 | * For 32 bit Operating Systems we need to go through the 32 Bit | ||
665 | * BIOS Service Directory | ||
666 | * For 64 bit Operating Systems we get that service through SMBIOS. | ||
667 | */ | ||
668 | retval = detect_cru_service(); | ||
669 | if (retval < 0) { | ||
670 | dev_warn(&dev->dev, | ||
671 | "Unable to detect the %d Bit CRU Service.\n", | ||
672 | HPWDT_ARCH); | ||
673 | return retval; | ||
674 | } | ||
675 | |||
676 | /* | ||
677 | * We know this is the only CRU call we need to make so lets keep as | ||
678 | * few instructions as possible once the NMI comes in. | ||
679 | */ | ||
680 | cmn_regs.u1.rah = 0x0D; | ||
681 | cmn_regs.u1.ral = 0x02; | ||
682 | |||
683 | /* | ||
684 | * If the priority is set to 1, then we will be put first on the | ||
685 | * die notify list to handle a critical NMI. The default is to | ||
686 | * be last so other users of the NMI signal can function. | ||
687 | */ | ||
688 | if (priority) | ||
689 | die_notifier.priority = 0x7FFFFFFF; | ||
690 | |||
691 | retval = register_die_notifier(&die_notifier); | ||
692 | if (retval != 0) { | ||
693 | dev_warn(&dev->dev, | ||
694 | "Unable to register a die notifier (err=%d).\n", | ||
695 | retval); | ||
696 | if (cru_rom_addr) | ||
697 | iounmap(cru_rom_addr); | ||
698 | } | ||
699 | |||
700 | dev_info(&dev->dev, | ||
701 | "HP Watchdog Timer Driver: NMI decoding initialized" | ||
702 | ", allow kernel dump: %s (default = 0/OFF)" | ||
703 | ", priority: %s (default = 0/LAST).\n", | ||
704 | (allow_kdump == 0) ? "OFF" : "ON", | ||
705 | (priority == 0) ? "LAST" : "FIRST"); | ||
706 | return 0; | ||
707 | } | ||
708 | |||
709 | static void __devexit hpwdt_exit_nmi_decoding(void) | ||
710 | { | ||
711 | unregister_die_notifier(&die_notifier); | ||
712 | if (cru_rom_addr) | ||
713 | iounmap(cru_rom_addr); | ||
714 | } | ||
657 | 715 | ||
658 | static int __devinit hpwdt_init_one(struct pci_dev *dev, | 716 | static int __devinit hpwdt_init_one(struct pci_dev *dev, |
659 | const struct pci_device_id *ent) | 717 | const struct pci_device_id *ent) |
@@ -697,42 +755,10 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, | |||
697 | if (hpwdt_change_timer(soft_margin)) | 755 | if (hpwdt_change_timer(soft_margin)) |
698 | hpwdt_change_timer(DEFAULT_MARGIN); | 756 | hpwdt_change_timer(DEFAULT_MARGIN); |
699 | 757 | ||
700 | /* | 758 | /* Initialize NMI Decoding functionality */ |
701 | * We need to map the ROM to get the CRU service. | 759 | retval = hpwdt_init_nmi_decoding(dev); |
702 | * For 32 bit Operating Systems we need to go through the 32 Bit | 760 | if (retval != 0) |
703 | * BIOS Service Directory | 761 | goto error_init_nmi_decoding; |
704 | * For 64 bit Operating Systems we get that service through SMBIOS. | ||
705 | */ | ||
706 | retval = detect_cru_service(); | ||
707 | if (retval < 0) { | ||
708 | dev_warn(&dev->dev, | ||
709 | "Unable to detect the %d Bit CRU Service.\n", | ||
710 | HPWDT_ARCH); | ||
711 | goto error_get_cru; | ||
712 | } | ||
713 | |||
714 | /* | ||
715 | * We know this is the only CRU call we need to make so lets keep as | ||
716 | * few instructions as possible once the NMI comes in. | ||
717 | */ | ||
718 | cmn_regs.u1.rah = 0x0D; | ||
719 | cmn_regs.u1.ral = 0x02; | ||
720 | |||
721 | /* | ||
722 | * If the priority is set to 1, then we will be put first on the | ||
723 | * die notify list to handle a critical NMI. The default is to | ||
724 | * be last so other users of the NMI signal can function. | ||
725 | */ | ||
726 | if (priority) | ||
727 | die_notifier.priority = 0x7FFFFFFF; | ||
728 | |||
729 | retval = register_die_notifier(&die_notifier); | ||
730 | if (retval != 0) { | ||
731 | dev_warn(&dev->dev, | ||
732 | "Unable to register a die notifier (err=%d).\n", | ||
733 | retval); | ||
734 | goto error_die_notifier; | ||
735 | } | ||
736 | 762 | ||
737 | retval = misc_register(&hpwdt_miscdev); | 763 | retval = misc_register(&hpwdt_miscdev); |
738 | if (retval < 0) { | 764 | if (retval < 0) { |
@@ -742,23 +768,14 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, | |||
742 | goto error_misc_register; | 768 | goto error_misc_register; |
743 | } | 769 | } |
744 | 770 | ||
745 | printk(KERN_INFO | 771 | dev_info(&dev->dev, "HP Watchdog Timer Driver: %s" |
746 | "hp Watchdog Timer Driver: %s" | 772 | ", timer margin: %d seconds (nowayout=%d).\n", |
747 | ", timer margin: %d seconds (nowayout=%d)" | 773 | HPWDT_VERSION, soft_margin, nowayout); |
748 | ", allow kernel dump: %s (default = 0/OFF)" | ||
749 | ", priority: %s (default = 0/LAST).\n", | ||
750 | HPWDT_VERSION, soft_margin, nowayout, | ||
751 | (allow_kdump == 0) ? "OFF" : "ON", | ||
752 | (priority == 0) ? "LAST" : "FIRST"); | ||
753 | |||
754 | return 0; | 774 | return 0; |
755 | 775 | ||
756 | error_misc_register: | 776 | error_misc_register: |
757 | unregister_die_notifier(&die_notifier); | 777 | hpwdt_exit_nmi_decoding(); |
758 | error_die_notifier: | 778 | error_init_nmi_decoding: |
759 | if (cru_rom_addr) | ||
760 | iounmap(cru_rom_addr); | ||
761 | error_get_cru: | ||
762 | pci_iounmap(dev, pci_mem_addr); | 779 | pci_iounmap(dev, pci_mem_addr); |
763 | error_pci_iomap: | 780 | error_pci_iomap: |
764 | pci_disable_device(dev); | 781 | pci_disable_device(dev); |
@@ -771,10 +788,7 @@ static void __devexit hpwdt_exit(struct pci_dev *dev) | |||
771 | hpwdt_stop(); | 788 | hpwdt_stop(); |
772 | 789 | ||
773 | misc_deregister(&hpwdt_miscdev); | 790 | misc_deregister(&hpwdt_miscdev); |
774 | unregister_die_notifier(&die_notifier); | 791 | hpwdt_exit_nmi_decoding(); |
775 | |||
776 | if (cru_rom_addr) | ||
777 | iounmap(cru_rom_addr); | ||
778 | pci_iounmap(dev, pci_mem_addr); | 792 | pci_iounmap(dev, pci_mem_addr); |
779 | pci_disable_device(dev); | 793 | pci_disable_device(dev); |
780 | } | 794 | } |