diff options
author | Thomas Mingarelli <Thomas.Mingarelli@hp.com> | 2011-07-26 09:05:53 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2011-07-28 04:00:56 -0400 |
commit | 5efc7a6222f6408d29d6beb1142a302f31dc9eac (patch) | |
tree | 972469ac8e95ef19ad7a858e8bfd66dcd2dc3f2e /drivers/watchdog | |
parent | 22602868865f630adab94c4419b3aeb414014865 (diff) |
watchdog: hpwdt: add next gen HP servers
This patch is required to enable hpwdt to work on next generation HP servers
with iLO.
Signed-off-by: Thomas Mingarelli <thomas.mingarelli@hp.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/hpwdt.c | 104 |
1 files changed, 77 insertions, 27 deletions
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 8cb26855bfed..410fba45378d 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
@@ -36,7 +36,7 @@ | |||
36 | #include <asm/cacheflush.h> | 36 | #include <asm/cacheflush.h> |
37 | #endif /* CONFIG_HPWDT_NMI_DECODING */ | 37 | #endif /* CONFIG_HPWDT_NMI_DECODING */ |
38 | 38 | ||
39 | #define HPWDT_VERSION "1.2.0" | 39 | #define HPWDT_VERSION "1.3.0" |
40 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) | 40 | #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) |
41 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) | 41 | #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) |
42 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) | 42 | #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) |
@@ -87,6 +87,19 @@ struct smbios_cru64_info { | |||
87 | }; | 87 | }; |
88 | #define SMBIOS_CRU64_INFORMATION 212 | 88 | #define SMBIOS_CRU64_INFORMATION 212 |
89 | 89 | ||
90 | /* type 219 */ | ||
91 | struct smbios_proliant_info { | ||
92 | u8 type; | ||
93 | u8 byte_length; | ||
94 | u16 handle; | ||
95 | u32 power_features; | ||
96 | u32 omega_features; | ||
97 | u32 reserved; | ||
98 | u32 misc_features; | ||
99 | }; | ||
100 | #define SMBIOS_ICRU_INFORMATION 219 | ||
101 | |||
102 | |||
90 | struct cmn_registers { | 103 | struct cmn_registers { |
91 | union { | 104 | union { |
92 | struct { | 105 | struct { |
@@ -132,6 +145,7 @@ struct cmn_registers { | |||
132 | static unsigned int hpwdt_nmi_decoding; | 145 | static unsigned int hpwdt_nmi_decoding; |
133 | static unsigned int allow_kdump; | 146 | static unsigned int allow_kdump; |
134 | static unsigned int priority; /* hpwdt at end of die_notify list */ | 147 | static unsigned int priority; /* hpwdt at end of die_notify list */ |
148 | static unsigned int is_icru; | ||
135 | static DEFINE_SPINLOCK(rom_lock); | 149 | static DEFINE_SPINLOCK(rom_lock); |
136 | static void *cru_rom_addr; | 150 | static void *cru_rom_addr; |
137 | static struct cmn_registers cmn_regs; | 151 | static struct cmn_registers cmn_regs; |
@@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, | |||
476 | goto out; | 490 | goto out; |
477 | 491 | ||
478 | spin_lock_irqsave(&rom_lock, rom_pl); | 492 | spin_lock_irqsave(&rom_lock, rom_pl); |
479 | if (!die_nmi_called) | 493 | if (!die_nmi_called && !is_icru) |
480 | asminline_call(&cmn_regs, cru_rom_addr); | 494 | asminline_call(&cmn_regs, cru_rom_addr); |
481 | die_nmi_called = 1; | 495 | die_nmi_called = 1; |
482 | spin_unlock_irqrestore(&rom_lock, rom_pl); | 496 | spin_unlock_irqrestore(&rom_lock, rom_pl); |
483 | if (cmn_regs.u1.ral == 0) { | 497 | if (!is_icru) { |
484 | printk(KERN_WARNING "hpwdt: An NMI occurred, " | 498 | if (cmn_regs.u1.ral == 0) { |
485 | "but unable to determine source.\n"); | 499 | printk(KERN_WARNING "hpwdt: An NMI occurred, " |
486 | } else { | 500 | "but unable to determine source.\n"); |
487 | if (allow_kdump) | 501 | } |
488 | hpwdt_stop(); | ||
489 | panic("An NMI occurred, please see the Integrated " | ||
490 | "Management Log for details.\n"); | ||
491 | } | 502 | } |
503 | |||
504 | if (allow_kdump) | ||
505 | hpwdt_stop(); | ||
506 | panic("An NMI occurred, please see the Integrated " | ||
507 | "Management Log for details.\n"); | ||
508 | |||
492 | out: | 509 | out: |
493 | return NOTIFY_OK; | 510 | return NOTIFY_OK; |
494 | } | 511 | } |
@@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) | |||
659 | } | 676 | } |
660 | #endif /* CONFIG_X86_LOCAL_APIC */ | 677 | #endif /* CONFIG_X86_LOCAL_APIC */ |
661 | 678 | ||
679 | /* | ||
680 | * dmi_find_icru | ||
681 | * | ||
682 | * Routine Description: | ||
683 | * This function checks whether or not we are on an iCRU-based server. | ||
684 | * This check is independent of architecture and needs to be made for | ||
685 | * any ProLiant system. | ||
686 | */ | ||
687 | static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy) | ||
688 | { | ||
689 | struct smbios_proliant_info *smbios_proliant_ptr; | ||
690 | |||
691 | if (dm->type == SMBIOS_ICRU_INFORMATION) { | ||
692 | smbios_proliant_ptr = (struct smbios_proliant_info *) dm; | ||
693 | if (smbios_proliant_ptr->misc_features & 0x01) | ||
694 | is_icru = 1; | ||
695 | } | ||
696 | } | ||
697 | |||
662 | static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) | 698 | static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) |
663 | { | 699 | { |
664 | int retval; | 700 | int retval; |
665 | 701 | ||
666 | /* | 702 | /* |
667 | * We need to map the ROM to get the CRU service. | 703 | * On typical CRU-based systems we need to map that service in |
668 | * For 32 bit Operating Systems we need to go through the 32 Bit | 704 | * the BIOS. For 32 bit Operating Systems we need to go through |
669 | * BIOS Service Directory | 705 | * the 32 Bit BIOS Service Directory. For 64 bit Operating |
670 | * For 64 bit Operating Systems we get that service through SMBIOS. | 706 | * Systems we get that service through SMBIOS. |
707 | * | ||
708 | * On systems that support the new iCRU service all we need to | ||
709 | * do is call dmi_walk to get the supported flag value and skip | ||
710 | * the old cru detect code. | ||
671 | */ | 711 | */ |
672 | retval = detect_cru_service(); | 712 | dmi_walk(dmi_find_icru, NULL); |
673 | if (retval < 0) { | 713 | if (!is_icru) { |
674 | dev_warn(&dev->dev, | 714 | |
675 | "Unable to detect the %d Bit CRU Service.\n", | 715 | /* |
676 | HPWDT_ARCH); | 716 | * We need to map the ROM to get the CRU service. |
677 | return retval; | 717 | * For 32 bit Operating Systems we need to go through the 32 Bit |
678 | } | 718 | * BIOS Service Directory |
719 | * For 64 bit Operating Systems we get that service through SMBIOS. | ||
720 | */ | ||
721 | retval = detect_cru_service(); | ||
722 | if (retval < 0) { | ||
723 | dev_warn(&dev->dev, | ||
724 | "Unable to detect the %d Bit CRU Service.\n", | ||
725 | HPWDT_ARCH); | ||
726 | return retval; | ||
727 | } | ||
679 | 728 | ||
680 | /* | 729 | /* |
681 | * We know this is the only CRU call we need to make so lets keep as | 730 | * We know this is the only CRU call we need to make so lets keep as |
682 | * few instructions as possible once the NMI comes in. | 731 | * few instructions as possible once the NMI comes in. |
683 | */ | 732 | */ |
684 | cmn_regs.u1.rah = 0x0D; | 733 | cmn_regs.u1.rah = 0x0D; |
685 | cmn_regs.u1.ral = 0x02; | 734 | cmn_regs.u1.ral = 0x02; |
735 | } | ||
686 | 736 | ||
687 | /* | 737 | /* |
688 | * If the priority is set to 1, then we will be put first on the | 738 | * If the priority is set to 1, then we will be put first on the |