Commit 5efc7a62 authored by Thomas Mingarelli's avatar Thomas Mingarelli Committed by Wim Van Sebroeck

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: default avatarThomas Mingarelli <thomas.mingarelli@hp.com>
Signed-off-by: default avatarWim Van Sebroeck <wim@iguana.be>
parent 22602868
...@@ -36,7 +36,7 @@ ...@@ -36,7 +36,7 @@
#include <asm/cacheflush.h> #include <asm/cacheflush.h>
#endif /* CONFIG_HPWDT_NMI_DECODING */ #endif /* CONFIG_HPWDT_NMI_DECODING */
#define HPWDT_VERSION "1.2.0" #define HPWDT_VERSION "1.3.0"
#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128)
#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
...@@ -87,6 +87,19 @@ struct smbios_cru64_info { ...@@ -87,6 +87,19 @@ struct smbios_cru64_info {
}; };
#define SMBIOS_CRU64_INFORMATION 212 #define SMBIOS_CRU64_INFORMATION 212
/* type 219 */
struct smbios_proliant_info {
u8 type;
u8 byte_length;
u16 handle;
u32 power_features;
u32 omega_features;
u32 reserved;
u32 misc_features;
};
#define SMBIOS_ICRU_INFORMATION 219
struct cmn_registers { struct cmn_registers {
union { union {
struct { struct {
...@@ -132,6 +145,7 @@ struct cmn_registers { ...@@ -132,6 +145,7 @@ struct cmn_registers {
static unsigned int hpwdt_nmi_decoding; static unsigned int hpwdt_nmi_decoding;
static unsigned int allow_kdump; static unsigned int allow_kdump;
static unsigned int priority; /* hpwdt at end of die_notify list */ static unsigned int priority; /* hpwdt at end of die_notify list */
static unsigned int is_icru;
static DEFINE_SPINLOCK(rom_lock); static DEFINE_SPINLOCK(rom_lock);
static void *cru_rom_addr; static void *cru_rom_addr;
static struct cmn_registers cmn_regs; static struct cmn_registers cmn_regs;
...@@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, ...@@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
goto out; goto out;
spin_lock_irqsave(&rom_lock, rom_pl); spin_lock_irqsave(&rom_lock, rom_pl);
if (!die_nmi_called) if (!die_nmi_called && !is_icru)
asminline_call(&cmn_regs, cru_rom_addr); asminline_call(&cmn_regs, cru_rom_addr);
die_nmi_called = 1; die_nmi_called = 1;
spin_unlock_irqrestore(&rom_lock, rom_pl); spin_unlock_irqrestore(&rom_lock, rom_pl);
if (cmn_regs.u1.ral == 0) { if (!is_icru) {
printk(KERN_WARNING "hpwdt: An NMI occurred, " if (cmn_regs.u1.ral == 0) {
"but unable to determine source.\n"); printk(KERN_WARNING "hpwdt: An NMI occurred, "
} else { "but unable to determine source.\n");
if (allow_kdump) }
hpwdt_stop();
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");
} }
if (allow_kdump)
hpwdt_stop();
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");
out: out:
return NOTIFY_OK; return NOTIFY_OK;
} }
...@@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) ...@@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
} }
#endif /* CONFIG_X86_LOCAL_APIC */ #endif /* CONFIG_X86_LOCAL_APIC */
/*
* dmi_find_icru
*
* Routine Description:
* This function checks whether or not we are on an iCRU-based server.
* This check is independent of architecture and needs to be made for
* any ProLiant system.
*/
static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy)
{
struct smbios_proliant_info *smbios_proliant_ptr;
if (dm->type == SMBIOS_ICRU_INFORMATION) {
smbios_proliant_ptr = (struct smbios_proliant_info *) dm;
if (smbios_proliant_ptr->misc_features & 0x01)
is_icru = 1;
}
}
static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev)
{ {
int retval; int retval;
/* /*
* We need to map the ROM to get the CRU service. * On typical CRU-based systems we need to map that service in
* For 32 bit Operating Systems we need to go through the 32 Bit * the BIOS. For 32 bit Operating Systems we need to go through
* BIOS Service Directory * the 32 Bit BIOS Service Directory. For 64 bit Operating
* For 64 bit Operating Systems we get that service through SMBIOS. * Systems we get that service through SMBIOS.
*
* On systems that support the new iCRU service all we need to
* do is call dmi_walk to get the supported flag value and skip
* the old cru detect code.
*/ */
retval = detect_cru_service(); dmi_walk(dmi_find_icru, NULL);
if (retval < 0) { if (!is_icru) {
dev_warn(&dev->dev,
"Unable to detect the %d Bit CRU Service.\n", /*
HPWDT_ARCH); * We need to map the ROM to get the CRU service.
return retval; * For 32 bit Operating Systems we need to go through the 32 Bit
} * BIOS Service Directory
* For 64 bit Operating Systems we get that service through SMBIOS.
*/
retval = detect_cru_service();
if (retval < 0) {
dev_warn(&dev->dev,
"Unable to detect the %d Bit CRU Service.\n",
HPWDT_ARCH);
return retval;
}
/* /*
* We know this is the only CRU call we need to make so lets keep as * We know this is the only CRU call we need to make so lets keep as
* few instructions as possible once the NMI comes in. * few instructions as possible once the NMI comes in.
*/ */
cmn_regs.u1.rah = 0x0D; cmn_regs.u1.rah = 0x0D;
cmn_regs.u1.ral = 0x02; cmn_regs.u1.ral = 0x02;
}
/* /*
* If the priority is set to 1, then we will be put first on the * If the priority is set to 1, then we will be put first on the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment