summaryrefslogtreecommitdiff
path: root/drivers/watchdog/hpwdt.c
diff options
context:
space:
mode:
authorThomas Mingarelli <Thomas.Mingarelli@hp.com>2011-07-26 14:05:53 +0100
committerWim Van Sebroeck <wim@iguana.be>2011-07-28 08:00:56 +0000
commit5efc7a6222f6408d29d6beb1142a302f31dc9eac (patch)
tree972469ac8e95ef19ad7a858e8bfd66dcd2dc3f2e /drivers/watchdog/hpwdt.c
parent22602868865f630adab94c4419b3aeb414014865 (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/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 @@
#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)
@@ -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 {
@@ -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;
@@ -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;
}
@@ -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