aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/hpwdt.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/hpwdt.c')
-rw-r--r--drivers/watchdog/hpwdt.c104
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 */
91struct 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
90struct cmn_registers { 103struct cmn_registers {
91 union { 104 union {
92 struct { 105 struct {
@@ -132,6 +145,7 @@ struct cmn_registers {
132static unsigned int hpwdt_nmi_decoding; 145static unsigned int hpwdt_nmi_decoding;
133static unsigned int allow_kdump; 146static unsigned int allow_kdump;
134static unsigned int priority; /* hpwdt at end of die_notify list */ 147static unsigned int priority; /* hpwdt at end of die_notify list */
148static unsigned int is_icru;
135static DEFINE_SPINLOCK(rom_lock); 149static DEFINE_SPINLOCK(rom_lock);
136static void *cru_rom_addr; 150static void *cru_rom_addr;
137static struct cmn_registers cmn_regs; 151static 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
492out: 509out:
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 */
687static 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
662static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) 698static 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