Skip to content

Commit

Permalink
watchdog: hpwdt: add next gen HP servers
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Thomas Mingarelli authored and Wim Van Sebroeck committed Jul 28, 2011
1 parent 2260286 commit 5efc7a6
Showing 1 changed file with 77 additions and 27 deletions.
104 changes: 77 additions & 27 deletions drivers/watchdog/hpwdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
#include <asm/cacheflush.h>
#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 TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000)
#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535)
Expand Down Expand Up @@ -87,6 +87,19 @@ struct smbios_cru64_info {
};
#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 {
union {
struct {
Expand Down Expand Up @@ -132,6 +145,7 @@ struct cmn_registers {
static unsigned int hpwdt_nmi_decoding;
static unsigned int allow_kdump;
static unsigned int priority; /* hpwdt at end of die_notify list */
static unsigned int is_icru;
static DEFINE_SPINLOCK(rom_lock);
static void *cru_rom_addr;
static struct cmn_registers cmn_regs;
Expand Down Expand Up @@ -476,19 +490,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason,
goto out;

spin_lock_irqsave(&rom_lock, rom_pl);
if (!die_nmi_called)
if (!die_nmi_called && !is_icru)
asminline_call(&cmn_regs, cru_rom_addr);
die_nmi_called = 1;
spin_unlock_irqrestore(&rom_lock, rom_pl);
if (cmn_regs.u1.ral == 0) {
printk(KERN_WARNING "hpwdt: An NMI occurred, "
"but unable to determine source.\n");
} else {
if (allow_kdump)
hpwdt_stop();
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");
if (!is_icru) {
if (cmn_regs.u1.ral == 0) {
printk(KERN_WARNING "hpwdt: An NMI occurred, "
"but unable to determine source.\n");
}
}

if (allow_kdump)
hpwdt_stop();
panic("An NMI occurred, please see the Integrated "
"Management Log for details.\n");

out:
return NOTIFY_OK;
}
Expand Down Expand Up @@ -659,30 +676,63 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev)
}
#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)
{
int retval;

/*
* We need to map the ROM to get the CRU service.
* 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.
* On typical CRU-based systems we need to map that service in
* the BIOS. 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.
*
* 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();
if (retval < 0) {
dev_warn(&dev->dev,
"Unable to detect the %d Bit CRU Service.\n",
HPWDT_ARCH);
return retval;
}
dmi_walk(dmi_find_icru, NULL);
if (!is_icru) {

/*
* We need to map the ROM to get the CRU service.
* 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
* few instructions as possible once the NMI comes in.
*/
cmn_regs.u1.rah = 0x0D;
cmn_regs.u1.ral = 0x02;
/*
* 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.
*/
cmn_regs.u1.rah = 0x0D;
cmn_regs.u1.ral = 0x02;
}

/*
* If the priority is set to 1, then we will be put first on the
Expand Down

0 comments on commit 5efc7a6

Please sign in to comment.