From a52e6d181d10202712fb8dc7e397a80599133733 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:50:50 -0600 Subject: [PATCH 01/12] watchdog: hpwdt (1/12): clean-up include-files. * remove unnecessary includes * We use a spinlock, but lacked the include * We need bitops.h for test_and_set_bit/clear_bit Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index fd312fc8940e..183b7a4525bd 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -16,30 +16,22 @@ #include #include #include -#include #include -#include #include +#include #include #include -#include #include #include #include #include #include #include -#include -#include -#include #include #include #include #include -#include -#include -#include -#include +#include #include #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ From 550d299eeb39cf8e2d12700585c490696ba34be8 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:50:54 -0600 Subject: [PATCH 02/12] watchdog: hpwdt (2/12): Group options that affect watchdog behavior together Reorganization only. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 183b7a4525bd..0ad9af2e0667 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -794,13 +794,13 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); module_param(soft_margin, int, 0); MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds"); -module_param(allow_kdump, int, 0); -MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); - module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +module_param(allow_kdump, int, 0); +MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); + module_param(priority, int, 0); MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last" " (default = 0/Last)\n"); From 923410d0bf80cb26744b366cadcd2917f4a36b25 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:50:54 -0600 Subject: [PATCH 03/12] watchdog: hpwdt (3/12): Group NMI sourcing specific items together * Group together includes specific to NMI sourcing * Group defines only used by NMI sourcing together * Group declarations specific to NMI sourcing together This gives a clean seperation of watchdog specific items and NMI sourcing specific items (which is needed for making it possible to build hpwdt without the NMI functionality). Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 49 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 0ad9af2e0667..f0ecb14990df 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -17,14 +17,11 @@ #include #include #include -#include #include #include #include #include -#include #include -#include #include #include #include @@ -32,14 +29,36 @@ #include #include #include +#include +#include +#include #include +#define HPWDT_VERSION "1.1.1" +#define DEFAULT_MARGIN 30 + +static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ +static unsigned int reload; /* the computed soft_margin */ +static int nowayout = WATCHDOG_NOWAYOUT; +static char expect_release; +static unsigned long hpwdt_is_open; + +static void __iomem *pci_mem_addr; /* the PCI-memory address */ +static unsigned long __iomem *hpwdt_timer_reg; +static unsigned long __iomem *hpwdt_timer_con; + +static struct pci_device_id hpwdt_devices[] = { + { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, + { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, + {0}, /* terminate list */ +}; +MODULE_DEVICE_TABLE(pci, hpwdt_devices); + #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ #define CRU_BIOS_SIGNATURE_VALUE 0x55524324 #define PCI_BIOS32_PARAGRAPH_LEN 16 #define PCI_ROM_BASE1 0x000F0000 #define ROM_SIZE 0x10000 -#define HPWDT_VERSION "1.1.1" struct bios32_service_dir { u32 signature; @@ -104,33 +123,13 @@ struct cmn_registers { u32 reflags; } __attribute__((packed)); -#define DEFAULT_MARGIN 30 -static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ -static unsigned int reload; /* the computed soft_margin */ -static int nowayout = WATCHDOG_NOWAYOUT; -static char expect_release; -static unsigned long hpwdt_is_open; -static unsigned int allow_kdump; static unsigned int hpwdt_nmi_sourcing; +static unsigned int allow_kdump; static unsigned int priority; /* hpwdt at end of die_notify list */ - -static void __iomem *pci_mem_addr; /* the PCI-memory address */ -static unsigned long __iomem *hpwdt_timer_reg; -static unsigned long __iomem *hpwdt_timer_con; - static DEFINE_SPINLOCK(rom_lock); - static void *cru_rom_addr; - static struct cmn_registers cmn_regs; -static struct pci_device_id hpwdt_devices[] = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, - { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, - {0}, /* terminate list */ -}; -MODULE_DEVICE_TABLE(pci, hpwdt_devices); - extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, unsigned long *pRomEntry); From 36e3ff44cebd7e46756dec88f30c982bebefdab7 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:50:57 -0600 Subject: [PATCH 04/12] watchdog: hpwdt (4/12): Despecificate driver from iLO2 This driver supports both iLO2 and iLO3, but our user-visible strings currently only reference iLO2. Let's just call it "iLO2+" to avoid having to update strings for each iLO generation. This driver doesn't support iLO ASICs prior to iLO2, but that is sufficiently explained in Kconfig. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 4 ++-- drivers/watchdog/hpwdt.c | 12 ++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 4d2992aadfb7..cee25e401440 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -574,11 +574,11 @@ config IT87_WDT be called it87_wdt. config HP_WATCHDOG - tristate "HP Proliant iLO 2 Hardware Watchdog Timer" + tristate "HP Proliant iLO2+ Hardware Watchdog Timer" depends on X86 help A software monitoring watchdog and NMI sourcing driver. This driver - will detect lockups and provide stack trace. Also, when an NMI + will detect lockups and provide a stack trace. Also, when an NMI occurs this driver will make the necessary BIOS calls to log the cause of the NMI. This is a driver that will only load on a HP ProLiant system with a minimum of iLO2 support. diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index f0ecb14990df..e18f6b9f7947 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -48,8 +48,8 @@ static unsigned long __iomem *hpwdt_timer_reg; static unsigned long __iomem *hpwdt_timer_con; static struct pci_device_id hpwdt_devices[] = { - { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, - { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, + { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ + { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ {0}, /* terminate list */ }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); @@ -548,7 +548,7 @@ static const struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, - .identity = "HP iLO2 HW Watchdog Timer", + .identity = "HP iLO2+ HW Watchdog Timer", }; static long hpwdt_ioctl(struct file *file, unsigned int cmd, @@ -654,13 +654,13 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, hpwdt_check_nmi_sourcing(dev); /* - * First let's find out if we are on an iLO2 server. We will + * First let's find out if we are on an iLO2+ server. We will * not run on a legacy ASM box. * So we only support the G5 ProLiant servers and higher. */ if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) { dev_warn(&dev->dev, - "This server does not have an iLO2 ASIC.\n"); + "This server does not have an iLO2+ ASIC.\n"); return -ENODEV; } @@ -674,7 +674,7 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, pci_mem_addr = pci_iomap(dev, 1, 0x80); if (!pci_mem_addr) { dev_warn(&dev->dev, - "Unable to detect the iLO2 server memory.\n"); + "Unable to detect the iLO2+ server memory.\n"); retval = -ENOMEM; goto error_pci_iomap; } From 6b7f3d5321fef4c050073ae08ed9db6c83bb85f1 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:50:59 -0600 Subject: [PATCH 05/12] watchdog: hpwdt (5/12): Make x86 assembly ifdef guard more strict The 32-bit assembly is guarded by an #ifndef CONFIG_X86_64. Kconfig prevents us from building this driver on !X86, so that happens to suffice - but we should really lock it down to #ifdef CONFIG_X86_32. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index e18f6b9f7947..77ca72c0c6d5 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -133,7 +133,7 @@ static struct cmn_registers cmn_regs; extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, unsigned long *pRomEntry); -#ifndef CONFIG_X86_64 +#ifdef CONFIG_X86_32 /* --32 Bit Bios------------------------------------------------------------ */ #define HPWDT_ARCH 32 @@ -322,8 +322,9 @@ static int __devinit detect_cru_service(void) iounmap(p); return rc; } - -#else +/* ------------------------------------------------------------------------- */ +#endif /* CONFIG_X86_32 */ +#ifdef CONFIG_X86_64 /* --64 Bit Bios------------------------------------------------------------ */ #define HPWDT_ARCH 64 @@ -401,10 +402,8 @@ static int __devinit detect_cru_service(void) /* if cru_rom_addr has been set then we found a CRU service */ return ((cru_rom_addr != NULL) ? 0 : -ENODEV); } - /* ------------------------------------------------------------------------- */ - -#endif +#endif /* CONFIG_X86_64 */ /* * Watchdog operations From e802e32d2b42ce1384baf4e150f444477729aad2 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Wed, 2 Jun 2010 16:23:39 -0600 Subject: [PATCH 06/12] watchdog: hpwdt (6/12): Introduce SECS_TO_TICKS() macro Define a macro to convert from seconds to timer ticks. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 77ca72c0c6d5..a5d36ae350dd 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -35,6 +35,7 @@ #include #define HPWDT_VERSION "1.1.1" +#define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) #define DEFAULT_MARGIN 30 static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ @@ -410,7 +411,7 @@ static int __devinit detect_cru_service(void) */ static void hpwdt_start(void) { - reload = (soft_margin * 1000) / 128; + reload = SECS_TO_TICKS(soft_margin); iowrite16(reload, hpwdt_timer_reg); iowrite16(0x85, hpwdt_timer_con); } @@ -443,7 +444,7 @@ static int hpwdt_change_timer(int new_margin) printk(KERN_DEBUG "hpwdt: New timer passed in is %d seconds.\n", new_margin); - reload = (soft_margin * 1000) / 128; + reload = SECS_TO_TICKS(soft_margin); return 0; } From 6f681c2eabbd8df062963c52abaa0c7c3b2c5a7d Mon Sep 17 00:00:00 2001 From: dann frazier Date: Wed, 2 Jun 2010 16:23:40 -0600 Subject: [PATCH 07/12] watchdog: hpwdt (7/12): allow full range of timer values supported by hardware The hpwdt timer is a 16 bit value with 128ms resolution. Let applications use this entire range. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index a5d36ae350dd..00299919df39 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -36,6 +36,8 @@ #define HPWDT_VERSION "1.1.1" #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) +#define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) +#define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) #define DEFAULT_MARGIN 30 static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ @@ -432,8 +434,7 @@ static void hpwdt_ping(void) static int hpwdt_change_timer(int new_margin) { - /* Arbitrary, can't find the card's limits */ - if (new_margin < 5 || new_margin > 600) { + if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) { printk(KERN_WARNING "hpwdt: New value passed in is invalid: %d seconds.\n", new_margin); From aae67f3602d8869c8ab1b34b6ba9206e9fff4b16 Mon Sep 17 00:00:00 2001 From: dann frazier Date: Wed, 2 Jun 2010 16:23:41 -0600 Subject: [PATCH 08/12] watchdog: hpwdt (8/12): implement WDIOC_GETTIMELEFT Let applications check the amount of time left before the watchdog will fire. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 00299919df39..554526cf3233 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -450,6 +450,11 @@ static int hpwdt_change_timer(int new_margin) return 0; } +static int hpwdt_time_left(void) +{ + return TICKS_TO_SECS(ioread16(hpwdt_timer_reg)); +} + /* * NMI Handler */ @@ -591,6 +596,10 @@ static long hpwdt_ioctl(struct file *file, unsigned int cmd, case WDIOC_GETTIMEOUT: ret = put_user(soft_margin, p); break; + + case WDIOC_GETTIMELEFT: + ret = put_user(hpwdt_time_left(), p); + break; } return ret; } From 243066bad7e4ff5072b4e67063c4298d5bbba9cd Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:50:49 -0600 Subject: [PATCH 09/12] watchdog: hpwdt (9/12): hpwdt_pretimeout reorganization Reorganize this function to remove excess indentation and highlight the single return code. (No functional change). Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 554526cf3233..7ce73170fa37 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -465,24 +465,26 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, static int die_nmi_called; if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) - return NOTIFY_OK; + goto out; - if (hpwdt_nmi_sourcing) { - spin_lock_irqsave(&rom_lock, rom_pl); - if (!die_nmi_called) - 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 (!hpwdt_nmi_sourcing) + goto out; + + spin_lock_irqsave(&rom_lock, rom_pl); + if (!die_nmi_called) + 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"); } +out: return NOTIFY_OK; } From 34572b29dd1db23a36f9cc46abf1c9acf85f8cfe Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:51:01 -0600 Subject: [PATCH 10/12] watchdog: hpwdt (10/12): Use "decoding" instead of "sourcing" The term "decoding" more clearly explains what hpwdt is doing. It isn't just finding the source of the interrupt, but rather aids in decoding what the interrupt means. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 7ce73170fa37..99aa76c489a3 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -126,7 +126,7 @@ struct cmn_registers { u32 reflags; } __attribute__((packed)); -static unsigned int hpwdt_nmi_sourcing; +static unsigned int hpwdt_nmi_decoding; static unsigned int allow_kdump; static unsigned int priority; /* hpwdt at end of die_notify list */ static DEFINE_SPINLOCK(rom_lock); @@ -467,7 +467,7 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) goto out; - if (!hpwdt_nmi_sourcing) + if (!hpwdt_nmi_decoding) goto out; spin_lock_irqsave(&rom_lock, rom_pl); @@ -634,23 +634,23 @@ static struct notifier_block die_notifier = { */ #ifdef ARCH_HAS_NMI_WATCHDOG -static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev) +static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) { /* * If nmi_watchdog is turned off then we can turn on - * our nmi sourcing capability. + * our nmi decoding capability. */ if (!nmi_watchdog_active()) - hpwdt_nmi_sourcing = 1; + hpwdt_nmi_decoding = 1; else - dev_warn(&dev->dev, "NMI sourcing is disabled. To enable this " + dev_warn(&dev->dev, "NMI decoding is disabled. To enable this " "functionality you must reboot with nmi_watchdog=0 " "and load the hpwdt driver with priority=1.\n"); } #else -static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev) +static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) { - dev_warn(&dev->dev, "NMI sourcing is disabled. " + dev_warn(&dev->dev, "NMI decoding is disabled. " "Your kernel does not support a NMI Watchdog.\n"); } #endif @@ -661,9 +661,9 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, int retval; /* - * Check if we can do NMI sourcing or not + * Check if we can do NMI decoding or not */ - hpwdt_check_nmi_sourcing(dev); + hpwdt_check_nmi_decoding(dev); /* * First let's find out if we are on an iLO2+ server. We will From 2ec7ed67dc1e4e57d891233f5014d25f43f941ff Mon Sep 17 00:00:00 2001 From: dann frazier Date: Wed, 28 Jul 2010 12:38:43 -0600 Subject: [PATCH 11/12] watchdog: hpwdt (11/12): move NMI-decoding init and exit to seperate functions Move NMI-decoding initialisation and exit code to seperate functions so that we can ifdef-out parts of it in the future. Also, this is for a device, so let's use dev_info instead of printk. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/hpwdt.c | 124 ++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 55 deletions(-) diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 99aa76c489a3..850f17877e9c 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -653,7 +653,65 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) dev_warn(&dev->dev, "NMI decoding is disabled. " "Your kernel does not support a NMI Watchdog.\n"); } -#endif +#endif /* ARCH_HAS_NMI_WATCHDOG */ + +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. + */ + 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; + + /* + * If the priority is set to 1, then we will be put first on the + * die notify list to handle a critical NMI. The default is to + * be last so other users of the NMI signal can function. + */ + if (priority) + die_notifier.priority = 0x7FFFFFFF; + + retval = register_die_notifier(&die_notifier); + if (retval != 0) { + dev_warn(&dev->dev, + "Unable to register a die notifier (err=%d).\n", + retval); + if (cru_rom_addr) + iounmap(cru_rom_addr); + } + + dev_info(&dev->dev, + "HP Watchdog Timer Driver: NMI decoding initialized" + ", allow kernel dump: %s (default = 0/OFF)" + ", priority: %s (default = 0/LAST).\n", + (allow_kdump == 0) ? "OFF" : "ON", + (priority == 0) ? "LAST" : "FIRST"); + return 0; +} + +static void __devexit hpwdt_exit_nmi_decoding(void) +{ + unregister_die_notifier(&die_notifier); + if (cru_rom_addr) + iounmap(cru_rom_addr); +} static int __devinit hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) @@ -697,42 +755,10 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, if (hpwdt_change_timer(soft_margin)) hpwdt_change_timer(DEFAULT_MARGIN); - /* - * 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); - goto error_get_cru; - } - - /* - * 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 - * die notify list to handle a critical NMI. The default is to - * be last so other users of the NMI signal can function. - */ - if (priority) - die_notifier.priority = 0x7FFFFFFF; - - retval = register_die_notifier(&die_notifier); - if (retval != 0) { - dev_warn(&dev->dev, - "Unable to register a die notifier (err=%d).\n", - retval); - goto error_die_notifier; - } + /* Initialize NMI Decoding functionality */ + retval = hpwdt_init_nmi_decoding(dev); + if (retval != 0) + goto error_init_nmi_decoding; retval = misc_register(&hpwdt_miscdev); if (retval < 0) { @@ -742,23 +768,14 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, goto error_misc_register; } - printk(KERN_INFO - "hp Watchdog Timer Driver: %s" - ", timer margin: %d seconds (nowayout=%d)" - ", allow kernel dump: %s (default = 0/OFF)" - ", priority: %s (default = 0/LAST).\n", - HPWDT_VERSION, soft_margin, nowayout, - (allow_kdump == 0) ? "OFF" : "ON", - (priority == 0) ? "LAST" : "FIRST"); - + dev_info(&dev->dev, "HP Watchdog Timer Driver: %s" + ", timer margin: %d seconds (nowayout=%d).\n", + HPWDT_VERSION, soft_margin, nowayout); return 0; error_misc_register: - unregister_die_notifier(&die_notifier); -error_die_notifier: - if (cru_rom_addr) - iounmap(cru_rom_addr); -error_get_cru: + hpwdt_exit_nmi_decoding(); +error_init_nmi_decoding: pci_iounmap(dev, pci_mem_addr); error_pci_iomap: pci_disable_device(dev); @@ -771,10 +788,7 @@ static void __devexit hpwdt_exit(struct pci_dev *dev) hpwdt_stop(); misc_deregister(&hpwdt_miscdev); - unregister_die_notifier(&die_notifier); - - if (cru_rom_addr) - iounmap(cru_rom_addr); + hpwdt_exit_nmi_decoding(); pci_iounmap(dev, pci_mem_addr); pci_disable_device(dev); } From 86ded1f35df32ad795cfc8cc1bdaeffbcaec0d5f Mon Sep 17 00:00:00 2001 From: dann frazier Date: Tue, 27 Jul 2010 17:51:02 -0600 Subject: [PATCH 12/12] watchdog: hpwdt (12/12): Make NMI decoding a compile-time option hpwdt is quite functional without the NMI decoding feature. This change lets users disable the NMI portion at compile-time via the new HPWDT_NMI_DECODING config option. Signed-off-by: dann frazier Acked-by: Thomas Mingarelli Signed-off-by: Wim Van Sebroeck --- drivers/watchdog/Kconfig | 17 +++++++++++------ drivers/watchdog/hpwdt.c | 27 ++++++++++++++++++++++++++- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index cee25e401440..b036677df8c4 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -578,12 +578,17 @@ config HP_WATCHDOG depends on X86 help A software monitoring watchdog and NMI sourcing driver. This driver - will detect lockups and provide a stack trace. Also, when an NMI - occurs this driver will make the necessary BIOS calls to log - the cause of the NMI. This is a driver that will only load on a - HP ProLiant system with a minimum of iLO2 support. - To compile this driver as a module, choose M here: the - module will be called hpwdt. + will detect lockups and provide a stack trace. This is a driver that + will only load on a HP ProLiant system with a minimum of iLO2 support. + To compile this driver as a module, choose M here: the module will be + called hpwdt. + +config HPWDT_NMI_DECODING + bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer" + depends on HP_WATCHDOG + help + When an NMI occurs this feature will make the necessary BIOS calls to + log the cause of the NMI. config SC1200_WDT tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog" diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 850f17877e9c..3d77116e4634 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -27,14 +27,16 @@ #include #include #include +#ifdef CONFIG_HPWDT_NMI_DECODING #include #include #include #include #include #include +#endif /* CONFIG_HPWDT_NMI_DECODING */ -#define HPWDT_VERSION "1.1.1" +#define HPWDT_VERSION "1.2.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) @@ -57,6 +59,7 @@ static struct pci_device_id hpwdt_devices[] = { }; MODULE_DEVICE_TABLE(pci, hpwdt_devices); +#ifdef CONFIG_HPWDT_NMI_DECODING #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ #define CRU_BIOS_SIGNATURE_VALUE 0x55524324 #define PCI_BIOS32_PARAGRAPH_LEN 16 @@ -407,6 +410,7 @@ static int __devinit detect_cru_service(void) } /* ------------------------------------------------------------------------- */ #endif /* CONFIG_X86_64 */ +#endif /* CONFIG_HPWDT_NMI_DECODING */ /* * Watchdog operations @@ -455,6 +459,7 @@ static int hpwdt_time_left(void) return TICKS_TO_SECS(ioread16(hpwdt_timer_reg)); } +#ifdef CONFIG_HPWDT_NMI_DECODING /* * NMI Handler */ @@ -487,6 +492,7 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, out: return NOTIFY_OK; } +#endif /* CONFIG_HPWDT_NMI_DECODING */ /* * /dev/watchdog handling @@ -624,15 +630,18 @@ static struct miscdevice hpwdt_miscdev = { .fops = &hpwdt_fops, }; +#ifdef CONFIG_HPWDT_NMI_DECODING static struct notifier_block die_notifier = { .notifier_call = hpwdt_pretimeout, .priority = 0, }; +#endif /* CONFIG_HPWDT_NMI_DECODING */ /* * Init & Exit */ +#ifdef CONFIG_HPWDT_NMI_DECODING #ifdef ARCH_HAS_NMI_WATCHDOG static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) { @@ -712,6 +721,20 @@ static void __devexit hpwdt_exit_nmi_decoding(void) if (cru_rom_addr) iounmap(cru_rom_addr); } +#else /* !CONFIG_HPWDT_NMI_DECODING */ +static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +{ +} + +static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) +{ + return 0; +} + +static void __devexit hpwdt_exit_nmi_decoding(void) +{ +} +#endif /* CONFIG_HPWDT_NMI_DECODING */ static int __devinit hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) @@ -823,12 +846,14 @@ module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +#ifdef CONFIG_HPWDT_NMI_DECODING module_param(allow_kdump, int, 0); MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); module_param(priority, int, 0); MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last" " (default = 0/Last)\n"); +#endif /* !CONFIG_HPWDT_NMI_DECODING */ module_init(hpwdt_init); module_exit(hpwdt_cleanup);