[WATCHDOG] hpwdt: Add NMI priority option
authorTom Mingarelli <thomas.mingarelli@hp.com>
Thu, 18 Jun 2009 23:28:57 +0000 (23:28 +0000)
committerWim Van Sebroeck <wim@iguana.be>
Tue, 23 Jun 2009 07:13:45 +0000 (07:13 +0000)
Add a priority option so that the user can choose if we do the NMI
first or last.

Signed-off-by: Thomas Mingarelli <thomas.mingarelli@hp.com>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
Documentation/watchdog/hpwdt.txt
drivers/watchdog/hpwdt.c

index 127839e530430916532de85f69e0e142a36f0188..9c24d5ffbb06be90460b055fd434f5e58dd9a661 100644 (file)
@@ -19,30 +19,41 @@ Last reviewed: 06/02/2009
  not be updated in a timely fashion and a hardware system reset (also known as
  an Automatic Server Recovery (ASR)) event will occur.
 
- The hpwdt driver also has three (3) module parameters. They are the following:
+ The hpwdt driver also has four (4) module parameters. They are the following:
 
  soft_margin - allows the user to set the watchdog timer value
  allow_kdump - allows the user to save off a kernel dump image after an NMI
  nowayout    - basic watchdog parameter that does not allow the timer to
                be restarted or an impending ASR to be escaped.
+ priority    - determines whether or not the hpwdt driver is first on the
+               die_notify list to handle NMIs or last. The default value
+               for this module parameter is 0 or LAST. If the user wants to
+               enable NMI sourcing then reload the hpwdt driver with
+               priority=1 (and boot with nmi_watchdog=0).
 
  NOTE: More information about watchdog drivers in general, including the ioctl
        interface to /dev/watchdog can be found in
        Documentation/watchdog/watchdog-api.txt and Documentation/IPMI.txt.
 
- The NMI sourcing capability is disabled when the driver discovers that the
- nmi_watchdog is turned on (nmi_watchdog = 1). This is due to the inability to
+ The priority parameter was introduced due to other kernel software that relied
+ on handling NMIs (like oprofile). Keeping hpwdt's priority at 0 (or LAST)
+ enables the users of NMIs for non critical events to be work as expected.
+
+ The NMI sourcing capability is disabled by default due to the inability to
  distinguish between "NMI Watchdog Ticks" and "HW generated NMI events" in the
  Linux kernel. What this means is that the hpwdt nmi handler code is called
  each time the NMI signal fires off. This could amount to several thousands of
  NMIs in a matter of seconds. If a user sees the Linux kernel's "dazed and
  confused" message in the logs or if the system gets into a hung state, then
- the user should reboot with nmi_watchdog=0.
+ the hpwdt driver can be reloaded with the "priority" module parameter set
+ (priority=1).
 
  1. If the kernel has not been booted with nmi_watchdog turned off then
     edit /boot/grub/menu.lst and place the nmi_watchdog=0 at the end of the
     currently booting kernel line.
  2. reboot the sever
+ 3. Once the system comes up perform a rmmod hpwdt
+ 4. insmod /lib/modules/`uname -r`/kernel/drivers/char/watchdog/hpwdt.ko priority=1
 
  Now, the hpwdt can successfully receive and source the NMI and provide a log
  message that details the reason for the NMI (as determined by the HP BIOS).
index c0b9169ba5d5f3d24db399b9683708cf16de988f..a6c5674c78e689414d1967d8b07fb90a28e12d3f 100644 (file)
@@ -120,7 +120,8 @@ static int nowayout = WATCHDOG_NOWAYOUT;
 static char expect_release;
 static unsigned long hpwdt_is_open;
 static unsigned int allow_kdump;
-static int hpwdt_nmi_sourcing;
+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;
@@ -623,7 +624,7 @@ static struct miscdevice hpwdt_miscdev = {
 
 static struct notifier_block die_notifier = {
        .notifier_call = hpwdt_pretimeout,
-       .priority = 0x7FFFFFFF,
+       .priority = 0,
 };
 
 /*
@@ -641,7 +642,8 @@ static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev)
                hpwdt_nmi_sourcing = 1;
        else
                dev_warn(&dev->dev, "NMI sourcing is disabled. To enable this "
-                       "functionality you must reboot with nmi_watchdog=0.\n");
+                       "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)
@@ -714,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,
@@ -733,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;
 
@@ -798,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);