diff options
Diffstat (limited to 'drivers/watchdog/hpwdt.c')
-rw-r--r-- | drivers/watchdog/hpwdt.c | 81 |
1 files changed, 63 insertions, 18 deletions
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 3137361ccbf..a6c5674c78e 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -19,6 +19,7 @@ #include <linux/interrupt.h> #include <linux/io.h> #include <linux/irq.h> +#include <linux/nmi.h> #include <linux/kernel.h> #include <linux/miscdevice.h> #include <linux/mm.h> @@ -47,7 +48,7 @@ #define PCI_BIOS32_PARAGRAPH_LEN 16 #define PCI_ROM_BASE1 0x000F0000 #define ROM_SIZE 0x10000 -#define HPWDT_VERSION "1.01" +#define HPWDT_VERSION "1.1.1" struct bios32_service_dir { u32 signature; @@ -119,6 +120,8 @@ 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 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; @@ -468,21 +471,22 @@ static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) return NOTIFY_OK; - 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) { + 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"); + } } - return NOTIFY_OK; } @@ -620,19 +624,46 @@ static struct miscdevice hpwdt_miscdev = { static struct notifier_block die_notifier = { .notifier_call = hpwdt_pretimeout, - .priority = 0x7FFFFFFF, + .priority = 0, }; /* * Init & Exit */ +#ifdef ARCH_HAS_NMI_WATCHDOG +static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev) +{ + /* + * If nmi_watchdog is turned off then we can turn on + * our nmi sourcing capability. + */ + if (!nmi_watchdog_active()) + hpwdt_nmi_sourcing = 1; + else + dev_warn(&dev->dev, "NMI sourcing 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) +{ + dev_warn(&dev->dev, "NMI sourcing is disabled. " + "Your kernel does not support a NMI Watchdog.\n"); +} +#endif + static int __devinit hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { int retval; /* + * Check if we can do NMI sourcing or not + */ + hpwdt_check_nmi_sourcing(dev); + + /* * 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. @@ -685,6 +716,14 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, 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, @@ -704,9 +743,11 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, printk(KERN_INFO "hp Watchdog Timer Driver: %s" ", timer margin: %d seconds (nowayout=%d)" - ", allow kernel dump: %s (default = 0/OFF).\n", + ", allow kernel dump: %s (default = 0/OFF)" + ", priority: %s (default = 0/LAST).\n", HPWDT_VERSION, soft_margin, nowayout, - (allow_kdump == 0) ? "OFF" : "ON"); + (allow_kdump == 0) ? "OFF" : "ON", + (priority == 0) ? "LAST" : "FIRST"); return 0; @@ -769,5 +810,9 @@ module_param(nowayout, int, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); +module_param(priority, int, 0); +MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last" + " (default = 0/Last)\n"); + module_init(hpwdt_init); module_exit(hpwdt_cleanup); |