watchdog: hpwdt: add next gen HP servers
authorThomas Mingarelli <Thomas.Mingarelli@hp.com>
Tue, 26 Jul 2011 13:05:53 +0000 (14:05 +0100)
committerWim Van Sebroeck <wim@iguana.be>
Thu, 28 Jul 2011 08:00:56 +0000 (08:00 +0000)
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>
drivers/watchdog/hpwdt.c

index 8cb26855bfede30eeb6782f693a29add442cdaa1..410fba45378d404f5ce4045faaf6f3c9782a957b 100644 (file)
@@ -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