Merge git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog

* git://git.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog:
watchdog: hpwdt (12/12): Make NMI decoding a compile-time option
watchdog: hpwdt (11/12): move NMI-decoding init and exit to seperate functions
watchdog: hpwdt (10/12): Use "decoding" instead of "sourcing"
watchdog: hpwdt (9/12): hpwdt_pretimeout reorganization
watchdog: hpwdt (8/12): implement WDIOC_GETTIMELEFT
watchdog: hpwdt (7/12): allow full range of timer values supported by hardware
watchdog: hpwdt (6/12): Introduce SECS_TO_TICKS() macro
watchdog: hpwdt (5/12): Make x86 assembly ifdef guard more strict
watchdog: hpwdt (4/12): Despecificate driver from iLO2
watchdog: hpwdt (3/12): Group NMI sourcing specific items together
watchdog: hpwdt (2/12): Group options that affect watchdog behavior together
watchdog: hpwdt (1/12): clean-up include-files.

+185 -138
+12 -7
drivers/watchdog/Kconfig
··· 574 574 be called it87_wdt. 575 575 576 576 config HP_WATCHDOG 577 - tristate "HP Proliant iLO 2 Hardware Watchdog Timer" 577 + tristate "HP Proliant iLO2+ Hardware Watchdog Timer" 578 578 depends on X86 579 579 help 580 580 A software monitoring watchdog and NMI sourcing driver. This driver 581 - will detect lockups and provide stack trace. Also, when an NMI 582 - occurs this driver will make the necessary BIOS calls to log 583 - the cause of the NMI. This is a driver that will only load on a 584 - HP ProLiant system with a minimum of iLO2 support. 585 - To compile this driver as a module, choose M here: the 586 - module will be called hpwdt. 581 + will detect lockups and provide a stack trace. This is a driver that 582 + will only load on a HP ProLiant system with a minimum of iLO2 support. 583 + To compile this driver as a module, choose M here: the module will be 584 + called hpwdt. 585 + 586 + config HPWDT_NMI_DECODING 587 + bool "NMI decoding support for the HP ProLiant iLO2+ Hardware Watchdog Timer" 588 + depends on HP_WATCHDOG 589 + help 590 + When an NMI occurs this feature will make the necessary BIOS calls to 591 + log the cause of the NMI. 587 592 588 593 config SC1200_WDT 589 594 tristate "National Semiconductor PC87307/PC97307 (ala SC1200) Watchdog"
+173 -131
drivers/watchdog/hpwdt.c
··· 16 16 #include <linux/device.h> 17 17 #include <linux/fs.h> 18 18 #include <linux/init.h> 19 - #include <linux/interrupt.h> 20 19 #include <linux/io.h> 21 - #include <linux/irq.h> 22 - #include <linux/nmi.h> 20 + #include <linux/bitops.h> 23 21 #include <linux/kernel.h> 24 22 #include <linux/miscdevice.h> 25 - #include <linux/mm.h> 26 23 #include <linux/module.h> 27 - #include <linux/kdebug.h> 28 24 #include <linux/moduleparam.h> 29 - #include <linux/notifier.h> 30 25 #include <linux/pci.h> 31 26 #include <linux/pci_ids.h> 32 - #include <linux/reboot.h> 33 - #include <linux/sched.h> 34 - #include <linux/timer.h> 35 27 #include <linux/types.h> 36 28 #include <linux/uaccess.h> 37 29 #include <linux/watchdog.h> 30 + #ifdef CONFIG_HPWDT_NMI_DECODING 38 31 #include <linux/dmi.h> 39 - #include <linux/efi.h> 40 - #include <linux/string.h> 41 - #include <linux/bootmem.h> 42 - #include <asm/desc.h> 32 + #include <linux/spinlock.h> 33 + #include <linux/nmi.h> 34 + #include <linux/kdebug.h> 35 + #include <linux/notifier.h> 43 36 #include <asm/cacheflush.h> 37 + #endif /* CONFIG_HPWDT_NMI_DECODING */ 44 38 39 + #define HPWDT_VERSION "1.2.0" 40 + #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) 41 + #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) 42 + #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) 43 + #define DEFAULT_MARGIN 30 44 + 45 + static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ 46 + static unsigned int reload; /* the computed soft_margin */ 47 + static int nowayout = WATCHDOG_NOWAYOUT; 48 + static char expect_release; 49 + static unsigned long hpwdt_is_open; 50 + 51 + static void __iomem *pci_mem_addr; /* the PCI-memory address */ 52 + static unsigned long __iomem *hpwdt_timer_reg; 53 + static unsigned long __iomem *hpwdt_timer_con; 54 + 55 + static struct pci_device_id hpwdt_devices[] = { 56 + { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ 57 + { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ 58 + {0}, /* terminate list */ 59 + }; 60 + MODULE_DEVICE_TABLE(pci, hpwdt_devices); 61 + 62 + #ifdef CONFIG_HPWDT_NMI_DECODING 45 63 #define PCI_BIOS32_SD_VALUE 0x5F32335F /* "_32_" */ 46 64 #define CRU_BIOS_SIGNATURE_VALUE 0x55524324 47 65 #define PCI_BIOS32_PARAGRAPH_LEN 16 48 66 #define PCI_ROM_BASE1 0x000F0000 49 67 #define ROM_SIZE 0x10000 50 - #define HPWDT_VERSION "1.1.1" 51 68 52 69 struct bios32_service_dir { 53 70 u32 signature; ··· 129 112 u32 reflags; 130 113 } __attribute__((packed)); 131 114 132 - #define DEFAULT_MARGIN 30 133 - static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ 134 - static unsigned int reload; /* the computed soft_margin */ 135 - static int nowayout = WATCHDOG_NOWAYOUT; 136 - static char expect_release; 137 - static unsigned long hpwdt_is_open; 115 + static unsigned int hpwdt_nmi_decoding; 138 116 static unsigned int allow_kdump; 139 - static unsigned int hpwdt_nmi_sourcing; 140 117 static unsigned int priority; /* hpwdt at end of die_notify list */ 141 - 142 - static void __iomem *pci_mem_addr; /* the PCI-memory address */ 143 - static unsigned long __iomem *hpwdt_timer_reg; 144 - static unsigned long __iomem *hpwdt_timer_con; 145 - 146 118 static DEFINE_SPINLOCK(rom_lock); 147 - 148 119 static void *cru_rom_addr; 149 - 150 120 static struct cmn_registers cmn_regs; 151 - 152 - static struct pci_device_id hpwdt_devices[] = { 153 - { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, 154 - { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, 155 - {0}, /* terminate list */ 156 - }; 157 - MODULE_DEVICE_TABLE(pci, hpwdt_devices); 158 121 159 122 extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, 160 123 unsigned long *pRomEntry); 161 124 162 - #ifndef CONFIG_X86_64 125 + #ifdef CONFIG_X86_32 163 126 /* --32 Bit Bios------------------------------------------------------------ */ 164 127 165 128 #define HPWDT_ARCH 32 ··· 328 331 iounmap(p); 329 332 return rc; 330 333 } 331 - 332 - #else 334 + /* ------------------------------------------------------------------------- */ 335 + #endif /* CONFIG_X86_32 */ 336 + #ifdef CONFIG_X86_64 333 337 /* --64 Bit Bios------------------------------------------------------------ */ 334 338 335 339 #define HPWDT_ARCH 64 ··· 408 410 /* if cru_rom_addr has been set then we found a CRU service */ 409 411 return ((cru_rom_addr != NULL) ? 0 : -ENODEV); 410 412 } 411 - 412 413 /* ------------------------------------------------------------------------- */ 413 - 414 - #endif 414 + #endif /* CONFIG_X86_64 */ 415 + #endif /* CONFIG_HPWDT_NMI_DECODING */ 415 416 416 417 /* 417 418 * Watchdog operations 418 419 */ 419 420 static void hpwdt_start(void) 420 421 { 421 - reload = (soft_margin * 1000) / 128; 422 + reload = SECS_TO_TICKS(soft_margin); 422 423 iowrite16(reload, hpwdt_timer_reg); 423 424 iowrite16(0x85, hpwdt_timer_con); 424 425 } ··· 438 441 439 442 static int hpwdt_change_timer(int new_margin) 440 443 { 441 - /* Arbitrary, can't find the card's limits */ 442 - if (new_margin < 5 || new_margin > 600) { 444 + if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) { 443 445 printk(KERN_WARNING 444 446 "hpwdt: New value passed in is invalid: %d seconds.\n", 445 447 new_margin); ··· 449 453 printk(KERN_DEBUG 450 454 "hpwdt: New timer passed in is %d seconds.\n", 451 455 new_margin); 452 - reload = (soft_margin * 1000) / 128; 456 + reload = SECS_TO_TICKS(soft_margin); 453 457 454 458 return 0; 455 459 } 456 460 461 + static int hpwdt_time_left(void) 462 + { 463 + return TICKS_TO_SECS(ioread16(hpwdt_timer_reg)); 464 + } 465 + 466 + #ifdef CONFIG_HPWDT_NMI_DECODING 457 467 /* 458 468 * NMI Handler 459 469 */ ··· 470 468 static int die_nmi_called; 471 469 472 470 if (ulReason != DIE_NMI && ulReason != DIE_NMI_IPI) 473 - return NOTIFY_OK; 471 + goto out; 474 472 475 - if (hpwdt_nmi_sourcing) { 476 - spin_lock_irqsave(&rom_lock, rom_pl); 477 - if (!die_nmi_called) 478 - asminline_call(&cmn_regs, cru_rom_addr); 479 - die_nmi_called = 1; 480 - spin_unlock_irqrestore(&rom_lock, rom_pl); 481 - if (cmn_regs.u1.ral == 0) { 482 - printk(KERN_WARNING "hpwdt: An NMI occurred, " 483 - "but unable to determine source.\n"); 484 - } else { 485 - if (allow_kdump) 486 - hpwdt_stop(); 487 - panic("An NMI occurred, please see the Integrated " 488 - "Management Log for details.\n"); 489 - } 473 + if (!hpwdt_nmi_decoding) 474 + goto out; 475 + 476 + spin_lock_irqsave(&rom_lock, rom_pl); 477 + if (!die_nmi_called) 478 + asminline_call(&cmn_regs, cru_rom_addr); 479 + die_nmi_called = 1; 480 + spin_unlock_irqrestore(&rom_lock, rom_pl); 481 + if (cmn_regs.u1.ral == 0) { 482 + printk(KERN_WARNING "hpwdt: An NMI occurred, " 483 + "but unable to determine source.\n"); 484 + } else { 485 + if (allow_kdump) 486 + hpwdt_stop(); 487 + panic("An NMI occurred, please see the Integrated " 488 + "Management Log for details.\n"); 490 489 } 490 + out: 491 491 return NOTIFY_OK; 492 492 } 493 + #endif /* CONFIG_HPWDT_NMI_DECODING */ 493 494 494 495 /* 495 496 * /dev/watchdog handling ··· 562 557 .options = WDIOF_SETTIMEOUT | 563 558 WDIOF_KEEPALIVEPING | 564 559 WDIOF_MAGICCLOSE, 565 - .identity = "HP iLO2 HW Watchdog Timer", 560 + .identity = "HP iLO2+ HW Watchdog Timer", 566 561 }; 567 562 568 563 static long hpwdt_ioctl(struct file *file, unsigned int cmd, ··· 604 599 case WDIOC_GETTIMEOUT: 605 600 ret = put_user(soft_margin, p); 606 601 break; 602 + 603 + case WDIOC_GETTIMELEFT: 604 + ret = put_user(hpwdt_time_left(), p); 605 + break; 607 606 } 608 607 return ret; 609 608 } ··· 630 621 .fops = &hpwdt_fops, 631 622 }; 632 623 624 + #ifdef CONFIG_HPWDT_NMI_DECODING 633 625 static struct notifier_block die_notifier = { 634 626 .notifier_call = hpwdt_pretimeout, 635 627 .priority = 0, 636 628 }; 629 + #endif /* CONFIG_HPWDT_NMI_DECODING */ 637 630 638 631 /* 639 632 * Init & Exit 640 633 */ 641 634 635 + #ifdef CONFIG_HPWDT_NMI_DECODING 642 636 #ifdef ARCH_HAS_NMI_WATCHDOG 643 - static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev) 637 + static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) 644 638 { 645 639 /* 646 640 * If nmi_watchdog is turned off then we can turn on 647 - * our nmi sourcing capability. 641 + * our nmi decoding capability. 648 642 */ 649 643 if (!nmi_watchdog_active()) 650 - hpwdt_nmi_sourcing = 1; 644 + hpwdt_nmi_decoding = 1; 651 645 else 652 - dev_warn(&dev->dev, "NMI sourcing is disabled. To enable this " 646 + dev_warn(&dev->dev, "NMI decoding is disabled. To enable this " 653 647 "functionality you must reboot with nmi_watchdog=0 " 654 648 "and load the hpwdt driver with priority=1.\n"); 655 649 } 656 650 #else 657 - static void __devinit hpwdt_check_nmi_sourcing(struct pci_dev *dev) 651 + static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) 658 652 { 659 - dev_warn(&dev->dev, "NMI sourcing is disabled. " 653 + dev_warn(&dev->dev, "NMI decoding is disabled. " 660 654 "Your kernel does not support a NMI Watchdog.\n"); 661 655 } 662 - #endif 656 + #endif /* ARCH_HAS_NMI_WATCHDOG */ 663 657 664 - static int __devinit hpwdt_init_one(struct pci_dev *dev, 665 - const struct pci_device_id *ent) 658 + static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) 666 659 { 667 660 int retval; 668 - 669 - /* 670 - * Check if we can do NMI sourcing or not 671 - */ 672 - hpwdt_check_nmi_sourcing(dev); 673 - 674 - /* 675 - * First let's find out if we are on an iLO2 server. We will 676 - * not run on a legacy ASM box. 677 - * So we only support the G5 ProLiant servers and higher. 678 - */ 679 - if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) { 680 - dev_warn(&dev->dev, 681 - "This server does not have an iLO2 ASIC.\n"); 682 - return -ENODEV; 683 - } 684 - 685 - if (pci_enable_device(dev)) { 686 - dev_warn(&dev->dev, 687 - "Not possible to enable PCI Device: 0x%x:0x%x.\n", 688 - ent->vendor, ent->device); 689 - return -ENODEV; 690 - } 691 - 692 - pci_mem_addr = pci_iomap(dev, 1, 0x80); 693 - if (!pci_mem_addr) { 694 - dev_warn(&dev->dev, 695 - "Unable to detect the iLO2 server memory.\n"); 696 - retval = -ENOMEM; 697 - goto error_pci_iomap; 698 - } 699 - hpwdt_timer_reg = pci_mem_addr + 0x70; 700 - hpwdt_timer_con = pci_mem_addr + 0x72; 701 - 702 - /* Make sure that we have a valid soft_margin */ 703 - if (hpwdt_change_timer(soft_margin)) 704 - hpwdt_change_timer(DEFAULT_MARGIN); 705 661 706 662 /* 707 663 * We need to map the ROM to get the CRU service. ··· 679 705 dev_warn(&dev->dev, 680 706 "Unable to detect the %d Bit CRU Service.\n", 681 707 HPWDT_ARCH); 682 - goto error_get_cru; 708 + return retval; 683 709 } 684 710 685 711 /* ··· 702 728 dev_warn(&dev->dev, 703 729 "Unable to register a die notifier (err=%d).\n", 704 730 retval); 705 - goto error_die_notifier; 731 + if (cru_rom_addr) 732 + iounmap(cru_rom_addr); 706 733 } 734 + 735 + dev_info(&dev->dev, 736 + "HP Watchdog Timer Driver: NMI decoding initialized" 737 + ", allow kernel dump: %s (default = 0/OFF)" 738 + ", priority: %s (default = 0/LAST).\n", 739 + (allow_kdump == 0) ? "OFF" : "ON", 740 + (priority == 0) ? "LAST" : "FIRST"); 741 + return 0; 742 + } 743 + 744 + static void __devexit hpwdt_exit_nmi_decoding(void) 745 + { 746 + unregister_die_notifier(&die_notifier); 747 + if (cru_rom_addr) 748 + iounmap(cru_rom_addr); 749 + } 750 + #else /* !CONFIG_HPWDT_NMI_DECODING */ 751 + static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) 752 + { 753 + } 754 + 755 + static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) 756 + { 757 + return 0; 758 + } 759 + 760 + static void __devexit hpwdt_exit_nmi_decoding(void) 761 + { 762 + } 763 + #endif /* CONFIG_HPWDT_NMI_DECODING */ 764 + 765 + static int __devinit hpwdt_init_one(struct pci_dev *dev, 766 + const struct pci_device_id *ent) 767 + { 768 + int retval; 769 + 770 + /* 771 + * Check if we can do NMI decoding or not 772 + */ 773 + hpwdt_check_nmi_decoding(dev); 774 + 775 + /* 776 + * First let's find out if we are on an iLO2+ server. We will 777 + * not run on a legacy ASM box. 778 + * So we only support the G5 ProLiant servers and higher. 779 + */ 780 + if (dev->subsystem_vendor != PCI_VENDOR_ID_HP) { 781 + dev_warn(&dev->dev, 782 + "This server does not have an iLO2+ ASIC.\n"); 783 + return -ENODEV; 784 + } 785 + 786 + if (pci_enable_device(dev)) { 787 + dev_warn(&dev->dev, 788 + "Not possible to enable PCI Device: 0x%x:0x%x.\n", 789 + ent->vendor, ent->device); 790 + return -ENODEV; 791 + } 792 + 793 + pci_mem_addr = pci_iomap(dev, 1, 0x80); 794 + if (!pci_mem_addr) { 795 + dev_warn(&dev->dev, 796 + "Unable to detect the iLO2+ server memory.\n"); 797 + retval = -ENOMEM; 798 + goto error_pci_iomap; 799 + } 800 + hpwdt_timer_reg = pci_mem_addr + 0x70; 801 + hpwdt_timer_con = pci_mem_addr + 0x72; 802 + 803 + /* Make sure that we have a valid soft_margin */ 804 + if (hpwdt_change_timer(soft_margin)) 805 + hpwdt_change_timer(DEFAULT_MARGIN); 806 + 807 + /* Initialize NMI Decoding functionality */ 808 + retval = hpwdt_init_nmi_decoding(dev); 809 + if (retval != 0) 810 + goto error_init_nmi_decoding; 707 811 708 812 retval = misc_register(&hpwdt_miscdev); 709 813 if (retval < 0) { ··· 791 739 goto error_misc_register; 792 740 } 793 741 794 - printk(KERN_INFO 795 - "hp Watchdog Timer Driver: %s" 796 - ", timer margin: %d seconds (nowayout=%d)" 797 - ", allow kernel dump: %s (default = 0/OFF)" 798 - ", priority: %s (default = 0/LAST).\n", 799 - HPWDT_VERSION, soft_margin, nowayout, 800 - (allow_kdump == 0) ? "OFF" : "ON", 801 - (priority == 0) ? "LAST" : "FIRST"); 802 - 742 + dev_info(&dev->dev, "HP Watchdog Timer Driver: %s" 743 + ", timer margin: %d seconds (nowayout=%d).\n", 744 + HPWDT_VERSION, soft_margin, nowayout); 803 745 return 0; 804 746 805 747 error_misc_register: 806 - unregister_die_notifier(&die_notifier); 807 - error_die_notifier: 808 - if (cru_rom_addr) 809 - iounmap(cru_rom_addr); 810 - error_get_cru: 748 + hpwdt_exit_nmi_decoding(); 749 + error_init_nmi_decoding: 811 750 pci_iounmap(dev, pci_mem_addr); 812 751 error_pci_iomap: 813 752 pci_disable_device(dev); ··· 811 768 hpwdt_stop(); 812 769 813 770 misc_deregister(&hpwdt_miscdev); 814 - unregister_die_notifier(&die_notifier); 815 - 816 - if (cru_rom_addr) 817 - iounmap(cru_rom_addr); 771 + hpwdt_exit_nmi_decoding(); 818 772 pci_iounmap(dev, pci_mem_addr); 819 773 pci_disable_device(dev); 820 774 } ··· 842 802 module_param(soft_margin, int, 0); 843 803 MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds"); 844 804 845 - module_param(allow_kdump, int, 0); 846 - MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); 847 - 848 805 module_param(nowayout, int, 0); 849 806 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 850 807 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 851 808 809 + #ifdef CONFIG_HPWDT_NMI_DECODING 810 + module_param(allow_kdump, int, 0); 811 + MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); 812 + 852 813 module_param(priority, int, 0); 853 814 MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last" 854 815 " (default = 0/Last)\n"); 816 + #endif /* !CONFIG_HPWDT_NMI_DECODING */ 855 817 856 818 module_init(hpwdt_init); 857 819 module_exit(hpwdt_cleanup);