diff options
| -rw-r--r-- | drivers/watchdog/hpwdt.c | 93 |
1 files changed, 50 insertions, 43 deletions
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index d039d5f2fd1c..a3765e0be4a8 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c | |||
| @@ -116,6 +116,7 @@ static unsigned int reload; /* the computed soft_margin */ | |||
| 116 | static int nowayout = WATCHDOG_NOWAYOUT; | 116 | static int nowayout = WATCHDOG_NOWAYOUT; |
| 117 | static char expect_release; | 117 | static char expect_release; |
| 118 | static unsigned long hpwdt_is_open; | 118 | static unsigned long hpwdt_is_open; |
| 119 | static unsigned int allow_kdump; | ||
| 119 | 120 | ||
| 120 | static void __iomem *pci_mem_addr; /* the PCI-memory address */ | 121 | static void __iomem *pci_mem_addr; /* the PCI-memory address */ |
| 121 | static unsigned long __iomem *hpwdt_timer_reg; | 122 | static unsigned long __iomem *hpwdt_timer_reg; |
| @@ -221,19 +222,19 @@ static int __devinit cru_detect(unsigned long map_entry, | |||
| 221 | 222 | ||
| 222 | if (cmn_regs.u1.ral != 0) { | 223 | if (cmn_regs.u1.ral != 0) { |
| 223 | printk(KERN_WARNING | 224 | printk(KERN_WARNING |
| 224 | "hpwdt: Call succeeded but with an error: 0x%x\n", | 225 | "hpwdt: Call succeeded but with an error: 0x%x\n", |
| 225 | cmn_regs.u1.ral); | 226 | cmn_regs.u1.ral); |
| 226 | } else { | 227 | } else { |
| 227 | physical_bios_base = cmn_regs.u2.rebx; | 228 | physical_bios_base = cmn_regs.u2.rebx; |
| 228 | physical_bios_offset = cmn_regs.u4.redx; | 229 | physical_bios_offset = cmn_regs.u4.redx; |
| 229 | cru_length = cmn_regs.u3.recx; | 230 | cru_length = cmn_regs.u3.recx; |
| 230 | cru_physical_address = | 231 | cru_physical_address = |
| 231 | physical_bios_base + physical_bios_offset; | 232 | physical_bios_base + physical_bios_offset; |
| 232 | 233 | ||
| 233 | /* If the values look OK, then map it in. */ | 234 | /* If the values look OK, then map it in. */ |
| 234 | if ((physical_bios_base + physical_bios_offset)) { | 235 | if ((physical_bios_base + physical_bios_offset)) { |
| 235 | cru_rom_addr = | 236 | cru_rom_addr = |
| 236 | ioremap(cru_physical_address, cru_length); | 237 | ioremap(cru_physical_address, cru_length); |
| 237 | if (cru_rom_addr) | 238 | if (cru_rom_addr) |
| 238 | retval = 0; | 239 | retval = 0; |
| 239 | } | 240 | } |
| @@ -356,7 +357,6 @@ asm(".text \n\t" | |||
| 356 | "call *%r12 \n\t" | 357 | "call *%r12 \n\t" |
| 357 | "pushfq \n\t" | 358 | "pushfq \n\t" |
| 358 | "popq %r12 \n\t" | 359 | "popq %r12 \n\t" |
| 359 | "popfq \n\t" | ||
| 360 | "movl %eax, (%r9) \n\t" | 360 | "movl %eax, (%r9) \n\t" |
| 361 | "movl %ebx, 4(%r9) \n\t" | 361 | "movl %ebx, 4(%r9) \n\t" |
| 362 | "movl %ecx, 8(%r9) \n\t" | 362 | "movl %ecx, 8(%r9) \n\t" |
| @@ -390,10 +390,10 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm) | |||
| 390 | smbios_cru64_ptr = (struct smbios_cru64_info *) dm; | 390 | smbios_cru64_ptr = (struct smbios_cru64_info *) dm; |
| 391 | if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { | 391 | if (smbios_cru64_ptr->signature == CRU_BIOS_SIGNATURE_VALUE) { |
| 392 | cru_physical_address = | 392 | cru_physical_address = |
| 393 | smbios_cru64_ptr->physical_address + | 393 | smbios_cru64_ptr->physical_address + |
| 394 | smbios_cru64_ptr->double_offset; | 394 | smbios_cru64_ptr->double_offset; |
| 395 | cru_rom_addr = ioremap(cru_physical_address, | 395 | cru_rom_addr = ioremap(cru_physical_address, |
| 396 | smbios_cru64_ptr->double_length); | 396 | smbios_cru64_ptr->double_length); |
| 397 | } | 397 | } |
| 398 | } | 398 | } |
| 399 | } | 399 | } |
| @@ -405,7 +405,7 @@ static int __devinit detect_cru_service(void) | |||
| 405 | dmi_walk(dmi_find_cru); | 405 | dmi_walk(dmi_find_cru); |
| 406 | 406 | ||
| 407 | /* if cru_rom_addr has been set then we found a CRU service */ | 407 | /* if cru_rom_addr has been set then we found a CRU service */ |
| 408 | return ((cru_rom_addr != NULL) ? 0: -ENODEV); | 408 | return ((cru_rom_addr != NULL) ? 0 : -ENODEV); |
| 409 | } | 409 | } |
| 410 | 410 | ||
| 411 | /* ------------------------------------------------------------------------- */ | 411 | /* ------------------------------------------------------------------------- */ |
| @@ -413,34 +413,6 @@ static int __devinit detect_cru_service(void) | |||
| 413 | #endif | 413 | #endif |
| 414 | 414 | ||
| 415 | /* | 415 | /* |
| 416 | * NMI Handler | ||
| 417 | */ | ||
| 418 | static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, | ||
| 419 | void *data) | ||
| 420 | { | ||
| 421 | unsigned long rom_pl; | ||
| 422 | static int die_nmi_called; | ||
| 423 | |||
| 424 | if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) | ||
| 425 | return NOTIFY_OK; | ||
| 426 | |||
| 427 | spin_lock_irqsave(&rom_lock, rom_pl); | ||
| 428 | if (!die_nmi_called) | ||
| 429 | asminline_call(&cmn_regs, cru_rom_addr); | ||
| 430 | die_nmi_called = 1; | ||
| 431 | spin_unlock_irqrestore(&rom_lock, rom_pl); | ||
| 432 | if (cmn_regs.u1.ral == 0) { | ||
| 433 | printk(KERN_WARNING "hpwdt: An NMI occurred, " | ||
| 434 | "but unable to determine source.\n"); | ||
| 435 | } else { | ||
| 436 | panic("An NMI occurred, please see the Integrated " | ||
| 437 | "Management Log for details.\n"); | ||
| 438 | } | ||
| 439 | |||
| 440 | return NOTIFY_STOP; | ||
| 441 | } | ||
| 442 | |||
| 443 | /* | ||
| 444 | * Watchdog operations | 416 | * Watchdog operations |
| 445 | */ | 417 | */ |
| 446 | static void hpwdt_start(void) | 418 | static void hpwdt_start(void) |
| @@ -484,6 +456,36 @@ static int hpwdt_change_timer(int new_margin) | |||
| 484 | } | 456 | } |
| 485 | 457 | ||
| 486 | /* | 458 | /* |
| 459 | * NMI Handler | ||
| 460 | */ | ||
| 461 | static int hpwdt_pretimeout(struct notifier_block *nb, unsigned long ulReason, | ||
| 462 | void *data) | ||
| 463 | { | ||
| 464 | unsigned long rom_pl; | ||
| 465 | static int die_nmi_called; | ||
| 466 | |||
| 467 | if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) | ||
| 468 | return NOTIFY_OK; | ||
| 469 | |||
| 470 | spin_lock_irqsave(&rom_lock, rom_pl); | ||
| 471 | if (!die_nmi_called) | ||
| 472 | asminline_call(&cmn_regs, cru_rom_addr); | ||
| 473 | die_nmi_called = 1; | ||
| 474 | spin_unlock_irqrestore(&rom_lock, rom_pl); | ||
| 475 | if (cmn_regs.u1.ral == 0) { | ||
| 476 | printk(KERN_WARNING "hpwdt: An NMI occurred, " | ||
| 477 | "but unable to determine source.\n"); | ||
| 478 | } else { | ||
| 479 | if (allow_kdump) | ||
| 480 | hpwdt_stop(); | ||
| 481 | panic("An NMI occurred, please see the Integrated " | ||
| 482 | "Management Log for details.\n"); | ||
| 483 | } | ||
| 484 | |||
| 485 | return NOTIFY_STOP; | ||
| 486 | } | ||
| 487 | |||
| 488 | /* | ||
| 487 | * /dev/watchdog handling | 489 | * /dev/watchdog handling |
| 488 | */ | 490 | */ |
| 489 | static int hpwdt_open(struct inode *inode, struct file *file) | 491 | static int hpwdt_open(struct inode *inode, struct file *file) |
| @@ -625,17 +627,18 @@ static struct notifier_block die_notifier = { | |||
| 625 | */ | 627 | */ |
| 626 | 628 | ||
| 627 | static int __devinit hpwdt_init_one(struct pci_dev *dev, | 629 | static int __devinit hpwdt_init_one(struct pci_dev *dev, |
| 628 | const struct pci_device_id *ent) | 630 | const struct pci_device_id *ent) |
| 629 | { | 631 | { |
| 630 | int retval; | 632 | int retval; |
| 631 | 633 | ||
| 632 | /* | 634 | /* |
| 633 | * First let's find out if we are on an iLO2 server. We will | 635 | * First let's find out if we are on an iLO2 server. We will |
| 634 | * not run on a legacy ASM box. | 636 | * not run on a legacy ASM box. |
| 637 | * So we only support the G5 ProLiant servers and higher. | ||
| 635 | */ | 638 | */ |
| 636 | if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) { | 639 | if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) { |
| 637 | dev_warn(&dev->dev, | 640 | dev_warn(&dev->dev, |
| 638 | "This server does not have an iLO2 ASIC.\n"); | 641 | "This server does not have an iLO2 ASIC.\n"); |
| 639 | return -ENODEV; | 642 | return -ENODEV; |
| 640 | } | 643 | } |
| 641 | 644 | ||
| @@ -669,7 +672,7 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, | |||
| 669 | retval = detect_cru_service(); | 672 | retval = detect_cru_service(); |
| 670 | if (retval < 0) { | 673 | if (retval < 0) { |
| 671 | dev_warn(&dev->dev, | 674 | dev_warn(&dev->dev, |
| 672 | "Unable to detect the %d Bit CRU Service.\n", | 675 | "Unable to detect the %d Bit CRU Service.\n", |
| 673 | HPWDT_ARCH); | 676 | HPWDT_ARCH); |
| 674 | goto error_get_cru; | 677 | goto error_get_cru; |
| 675 | } | 678 | } |
| @@ -684,7 +687,7 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, | |||
| 684 | retval = register_die_notifier(&die_notifier); | 687 | retval = register_die_notifier(&die_notifier); |
| 685 | if (retval != 0) { | 688 | if (retval != 0) { |
| 686 | dev_warn(&dev->dev, | 689 | dev_warn(&dev->dev, |
| 687 | "Unable to register a die notifier (err=%d).\n", | 690 | "Unable to register a die notifier (err=%d).\n", |
| 688 | retval); | 691 | retval); |
| 689 | goto error_die_notifier; | 692 | goto error_die_notifier; |
| 690 | } | 693 | } |
| @@ -699,8 +702,9 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, | |||
| 699 | 702 | ||
| 700 | printk(KERN_INFO | 703 | printk(KERN_INFO |
| 701 | "hp Watchdog Timer Driver: 1.00" | 704 | "hp Watchdog Timer Driver: 1.00" |
| 702 | ", timer margin: %d seconds( nowayout=%d).\n", | 705 | ", timer margin: %d seconds (nowayout=%d)" |
| 703 | soft_margin, nowayout); | 706 | ", allow kernel dump: %s (default = 0/OFF).\n", |
| 707 | soft_margin, nowayout, (allow_kdump == 0) ? "OFF" : "ON"); | ||
| 704 | 708 | ||
| 705 | return 0; | 709 | return 0; |
| 706 | 710 | ||
| @@ -755,6 +759,9 @@ MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | |||
| 755 | module_param(soft_margin, int, 0); | 759 | module_param(soft_margin, int, 0); |
| 756 | MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds"); | 760 | MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds"); |
| 757 | 761 | ||
| 762 | module_param(allow_kdump, int, 0); | ||
| 763 | MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); | ||
| 764 | |||
| 758 | module_param(nowayout, int, 0); | 765 | module_param(nowayout, int, 0); |
| 759 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 766 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
| 760 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 767 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
