Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-wat…
Browse files Browse the repository at this point in the history
…chdog

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
  [WATCHDOG] hpwdt: Add NMI sourcing
  [WATCHDOG] iTCO_wdt: Fix ICH7+ reboot issue.
  [WATCHDOG] iTCO_wdt: fix memory corruption when RCBA is disabled by hardware
  [WATCHDOG] Correct WDIOF_MAGICCLOSE flag
  [WATCHDOG] move platform probe and remove function to devinit and devexit
  [WATCHDOG] Some more general cleanup
  [WATCHDOG] iTCO_wdt: Cleanup code
  • Loading branch information
Linus Torvalds committed Jun 18, 2009
2 parents dcce284 + 47bece8 commit 9e3e4b1
Show file tree
Hide file tree
Showing 30 changed files with 335 additions and 121 deletions.
84 changes: 84 additions & 0 deletions Documentation/watchdog/hpwdt.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
Last reviewed: 06/02/2009

HP iLO2 NMI Watchdog Driver
NMI sourcing for iLO2 based ProLiant Servers
Documentation and Driver by
Thomas Mingarelli <thomas.mingarelli@hp.com>

The HP iLO2 NMI Watchdog driver is a kernel module that provides basic
watchdog functionality and the added benefit of NMI sourcing. Both the
watchdog functionality and the NMI sourcing capability need to be enabled
by the user. Remember that the two modes are not dependant on one another.
A user can have the NMI sourcing without the watchdog timer and vice-versa.

Watchdog functionality is enabled like any other common watchdog driver. That
is, an application needs to be started that kicks off the watchdog timer. A
basic application exists in the Documentation/watchdog/src directory called
watchdog-test.c. Simply compile the C file and kick it off. If the system
gets into a bad state and hangs, the HP ProLiant iLO 2 timer register will
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:

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.

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
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.

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

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).

Below is a list of NMIs the HP BIOS understands along with the associated
code (reason):

No source found 00h

Uncorrectable Memory Error 01h

ASR NMI 1Bh

PCI Parity Error 20h

NMI Button Press 27h

SB_BUS_NMI 28h

ILO Doorbell NMI 29h

ILO IOP NMI 2Ah

ILO Watchdog NMI 2Bh

Proc Throt NMI 2Ch

Front Side Bus NMI 2Dh

PCI Express Error 2Fh

DMA controller NMI 30h

Hypertransport/CSI Error 31h



-- Tom Mingarelli
(thomas.mingarelli@hp.com)
15 changes: 11 additions & 4 deletions drivers/watchdog/alim7101_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,8 @@ static int wdt_notify_sys(struct notifier_block *this,
* watchdog on reboot with no heartbeat
*/
wdt_change(WDT_ENABLE);
printk(KERN_INFO PFX "Watchdog timer is now enabled with no heartbeat - should reboot in ~1 second.\n");
printk(KERN_INFO PFX "Watchdog timer is now enabled "
"with no heartbeat - should reboot in ~1 second.\n");
}
return NOTIFY_DONE;
}
Expand Down Expand Up @@ -374,12 +375,17 @@ static int __init alim7101_wdt_init(void)
pci_dev_put(ali1543_south);
if ((tmp & 0x1e) == 0x00) {
if (!use_gpio) {
printk(KERN_INFO PFX "Detected old alim7101 revision 'a1d'. If this is a cobalt board, set the 'use_gpio' module parameter.\n");
printk(KERN_INFO PFX
"Detected old alim7101 revision 'a1d'. "
"If this is a cobalt board, set the 'use_gpio' "
"module parameter.\n");
goto err_out;
}
nowayout = 1;
} else if ((tmp & 0x1e) != 0x12 && (tmp & 0x1e) != 0x00) {
printk(KERN_INFO PFX "ALi 1543 South-Bridge does not have the correct revision number (???1001?) - WDT not set\n");
printk(KERN_INFO PFX
"ALi 1543 South-Bridge does not have the correct "
"revision number (???1001?) - WDT not set\n");
goto err_out;
}

Expand Down Expand Up @@ -409,7 +415,8 @@ static int __init alim7101_wdt_init(void)
if (nowayout)
__module_get(THIS_MODULE);

printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. timeout=%d sec (nowayout=%d)\n",
printk(KERN_INFO PFX "WDT driver for ALi M7101 initialised. "
"timeout=%d sec (nowayout=%d)\n",
timeout, nowayout);
return 0;

Expand Down
3 changes: 2 additions & 1 deletion drivers/watchdog/ar7_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,8 @@ static long ar7_wdt_ioctl(struct file *file,
static struct watchdog_info ident = {
.identity = LONGNAME,
.firmware_version = 1,
.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING),
.options = (WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE),
};
int new_margin;

Expand Down
3 changes: 2 additions & 1 deletion drivers/watchdog/at91rm9200_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,8 @@ static int __init at91_wdt_init(void)
if not reset to the default */
if (at91_wdt_settimeout(wdt_time)) {
at91_wdt_settimeout(WDT_DEFAULT_TIME);
pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256, using %d\n", wdt_time);
pr_info("at91_wdt: wdt_time value must be 1 <= wdt_time <= 256"
", using %d\n", wdt_time);
}

return platform_driver_register(&at91wdt_driver);
Expand Down
3 changes: 2 additions & 1 deletion drivers/watchdog/at91sam9_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,8 @@ static int at91_wdt_settimeout(unsigned int timeout)

static const struct watchdog_info at91_wdt_info = {
.identity = DRV_NAME,
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
.options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
WDIOF_MAGICCLOSE,
};

/*
Expand Down
14 changes: 10 additions & 4 deletions drivers/watchdog/bfin_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,15 @@
#include <linux/uaccess.h>
#include <asm/blackfin.h>

#define stamp(fmt, args...) pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stamp(fmt, args...) \
pr_debug("%s:%i: " fmt "\n", __func__, __LINE__, ## args)
#define stampit() stamp("here i am")
#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define pr_init(fmt, args...) ({ static const __initconst char __fmt[] = fmt; printk(__fmt, ## args); })
#define pr_devinit(fmt, args...) \
({ static const __devinitconst char __fmt[] = fmt; \
printk(__fmt, ## args); })
#define pr_init(fmt, args...) \
({ static const __initconst char __fmt[] = fmt; \
printk(__fmt, ## args); })

#define WATCHDOG_NAME "bfin-wdt"
#define PFX WATCHDOG_NAME ": "
Expand Down Expand Up @@ -476,7 +481,8 @@ static int __init bfin_wdt_init(void)
return ret;
}

bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME, -1, NULL, 0);
bfin_wdt_device = platform_device_register_simple(WATCHDOG_NAME,
-1, NULL, 0);
if (IS_ERR(bfin_wdt_device)) {
pr_init(KERN_ERR PFX "unable to register device\n");
platform_driver_unregister(&bfin_wdt_driver);
Expand Down
6 changes: 3 additions & 3 deletions drivers/watchdog/cpwd.c
Original file line number Diff line number Diff line change
Expand Up @@ -154,9 +154,9 @@ static struct cpwd *cpwd_device;

static struct timer_list cpwd_timer;

static int wd0_timeout = 0;
static int wd1_timeout = 0;
static int wd2_timeout = 0;
static int wd0_timeout;
static int wd1_timeout;
static int wd2_timeout;

module_param(wd0_timeout, int, 0);
MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
Expand Down
6 changes: 3 additions & 3 deletions drivers/watchdog/davinci_wdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ static struct miscdevice davinci_wdt_miscdev = {
.fops = &davinci_wdt_fops,
};

static int davinci_wdt_probe(struct platform_device *pdev)
static int __devinit davinci_wdt_probe(struct platform_device *pdev)
{
int ret = 0, size;
struct resource *res;
Expand Down Expand Up @@ -237,7 +237,7 @@ static int davinci_wdt_probe(struct platform_device *pdev)
return ret;
}

static int davinci_wdt_remove(struct platform_device *pdev)
static int __devexit davinci_wdt_remove(struct platform_device *pdev)
{
misc_deregister(&davinci_wdt_miscdev);
if (wdt_mem) {
Expand All @@ -254,7 +254,7 @@ static struct platform_driver platform_wdt_driver = {
.owner = THIS_MODULE,
},
.probe = davinci_wdt_probe,
.remove = davinci_wdt_remove,
.remove = __devexit_p(davinci_wdt_remove),
};

static int __init davinci_wdt_init(void)
Expand Down
59 changes: 44 additions & 15 deletions drivers/watchdog/hpwdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -119,6 +120,7 @@ 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 void __iomem *pci_mem_addr; /* the PCI-memory address */
static unsigned long __iomem *hpwdt_timer_reg;
Expand Down Expand Up @@ -468,21 +470,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;
}

Expand Down Expand Up @@ -627,11 +630,37 @@ static struct notifier_block die_notifier = {
* 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.\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.
Expand Down
Loading

0 comments on commit 9e3e4b1

Please sign in to comment.