diff options
Diffstat (limited to 'drivers/watchdog/hpwdt.c')
| -rw-r--r-- | drivers/watchdog/hpwdt.c | 174 |
1 files changed, 89 insertions, 85 deletions
diff --git a/drivers/watchdog/hpwdt.c b/drivers/watchdog/hpwdt.c index 8464ea1c36a..75d2243b94f 100644 --- a/drivers/watchdog/hpwdt.c +++ b/drivers/watchdog/hpwdt.c @@ -13,9 +13,10 @@ * */ +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + #include <linux/device.h> #include <linux/fs.h> -#include <linux/init.h> #include <linux/io.h> #include <linux/bitops.h> #include <linux/kernel.h> @@ -37,7 +38,7 @@ #endif /* CONFIG_HPWDT_NMI_DECODING */ #include <asm/nmi.h> -#define HPWDT_VERSION "1.3.0" +#define HPWDT_VERSION "1.3.3" #define SECS_TO_TICKS(secs) ((secs) * 1000 / 128) #define TICKS_TO_SECS(ticks) ((ticks) * 128 / 1000) #define HPWDT_MAX_TIMER TICKS_TO_SECS(65535) @@ -45,7 +46,7 @@ static unsigned int soft_margin = DEFAULT_MARGIN; /* in seconds */ static unsigned int reload; /* the computed soft_margin */ -static int nowayout = WATCHDOG_NOWAYOUT; +static bool nowayout = WATCHDOG_NOWAYOUT; static char expect_release; static unsigned long hpwdt_is_open; @@ -53,7 +54,7 @@ static void __iomem *pci_mem_addr; /* the PCI-memory address */ static unsigned long __iomem *hpwdt_timer_reg; static unsigned long __iomem *hpwdt_timer_con; -static DEFINE_PCI_DEVICE_TABLE(hpwdt_devices) = { +static const struct pci_device_id hpwdt_devices[] = { { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB203) }, /* iLO2 */ { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3306) }, /* iLO3 */ {0}, /* terminate list */ @@ -144,9 +145,9 @@ struct cmn_registers { } __attribute__((packed)); static unsigned int hpwdt_nmi_decoding; -static unsigned int allow_kdump; -static unsigned int priority; /* hpwdt at end of die_notify list */ +static unsigned int allow_kdump = 1; static unsigned int is_icru; +static unsigned int is_uefi; static DEFINE_SPINLOCK(rom_lock); static void *cru_rom_addr; static struct cmn_registers cmn_regs; @@ -160,7 +161,8 @@ extern asmlinkage void asminline_call(struct cmn_registers *pi86Regs, #define HPWDT_ARCH 32 asm(".text \n\t" - ".align 4 \n" + ".align 4 \n\t" + ".globl asminline_call \n" "asminline_call: \n\t" "pushl %ebp \n\t" "movl %esp, %ebp \n\t" @@ -211,7 +213,7 @@ asm(".text \n\t" * 0 : SUCCESS * <0 : FAILURE */ -static int __devinit cru_detect(unsigned long map_entry, +static int cru_detect(unsigned long map_entry, unsigned long map_offset) { void *bios32_map; @@ -231,12 +233,11 @@ static int __devinit cru_detect(unsigned long map_entry, cmn_regs.u1.reax = CRU_BIOS_SIGNATURE_VALUE; - set_memory_x((unsigned long)bios32_entrypoint, (2 * PAGE_SIZE)); + set_memory_x((unsigned long)bios32_map, 2); asminline_call(&cmn_regs, bios32_entrypoint); if (cmn_regs.u1.ral != 0) { - printk(KERN_WARNING - "hpwdt: Call succeeded but with an error: 0x%x\n", + pr_warn("Call succeeded but with an error: 0x%x\n", cmn_regs.u1.ral); } else { physical_bios_base = cmn_regs.u2.rebx; @@ -250,19 +251,16 @@ static int __devinit cru_detect(unsigned long map_entry, cru_rom_addr = ioremap(cru_physical_address, cru_length); if (cru_rom_addr) { - set_memory_x((unsigned long)cru_rom_addr, cru_length); + set_memory_x((unsigned long)cru_rom_addr & PAGE_MASK, + (cru_length + PAGE_SIZE - 1) >> PAGE_SHIFT); retval = 0; } } - printk(KERN_DEBUG "hpwdt: CRU Base Address: 0x%lx\n", - physical_bios_base); - printk(KERN_DEBUG "hpwdt: CRU Offset Address: 0x%lx\n", - physical_bios_offset); - printk(KERN_DEBUG "hpwdt: CRU Length: 0x%lx\n", - cru_length); - printk(KERN_DEBUG "hpwdt: CRU Mapped Address: %p\n", - &cru_rom_addr); + pr_debug("CRU Base Address: 0x%lx\n", physical_bios_base); + pr_debug("CRU Offset Address: 0x%lx\n", physical_bios_offset); + pr_debug("CRU Length: 0x%lx\n", cru_length); + pr_debug("CRU Mapped Address: %p\n", &cru_rom_addr); } iounmap(bios32_map); return retval; @@ -271,7 +269,7 @@ static int __devinit cru_detect(unsigned long map_entry, /* * bios_checksum */ -static int __devinit bios_checksum(const char __iomem *ptr, int len) +static int bios_checksum(const char __iomem *ptr, int len) { char sum = 0; int i; @@ -296,7 +294,7 @@ static int __devinit bios_checksum(const char __iomem *ptr, int len) * 0 : SUCCESS * <0 : FAILURE */ -static int __devinit bios32_present(const char __iomem *p) +static int bios32_present(const char __iomem *p) { struct bios32_service_dir *bios_32_ptr; int length; @@ -326,7 +324,7 @@ static int __devinit bios32_present(const char __iomem *p) return -ENODEV; } -static int __devinit detect_cru_service(void) +static int detect_cru_service(void) { char __iomem *p, *q; int rc = -1; @@ -354,7 +352,8 @@ static int __devinit detect_cru_service(void) #define HPWDT_ARCH 64 asm(".text \n\t" - ".align 4 \n" + ".align 4 \n\t" + ".globl asminline_call \n" "asminline_call: \n\t" "pushq %rbp \n\t" "movq %rsp, %rbp \n\t" @@ -398,7 +397,7 @@ asm(".text \n\t" * This function checks whether or not a SMBIOS/DMI record is * the 64bit CRU info or not */ -static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy) +static void dmi_find_cru(const struct dmi_header *dm, void *dummy) { struct smbios_cru64_info *smbios_cru64_ptr; unsigned long cru_physical_address; @@ -417,7 +416,7 @@ static void __devinit dmi_find_cru(const struct dmi_header *dm, void *dummy) } } -static int __devinit detect_cru_service(void) +static int detect_cru_service(void) { cru_rom_addr = NULL; @@ -437,16 +436,16 @@ static void hpwdt_start(void) { reload = SECS_TO_TICKS(soft_margin); iowrite16(reload, hpwdt_timer_reg); - iowrite16(0x85, hpwdt_timer_con); + iowrite8(0x85, hpwdt_timer_con); } static void hpwdt_stop(void) { unsigned long data; - data = ioread16(hpwdt_timer_con); + data = ioread8(hpwdt_timer_con); data &= 0xFE; - iowrite16(data, hpwdt_timer_con); + iowrite8(data, hpwdt_timer_con); } static void hpwdt_ping(void) @@ -457,16 +456,13 @@ static void hpwdt_ping(void) static int hpwdt_change_timer(int new_margin) { if (new_margin < 1 || new_margin > HPWDT_MAX_TIMER) { - printk(KERN_WARNING - "hpwdt: New value passed in is invalid: %d seconds.\n", + pr_warn("New value passed in is invalid: %d seconds\n", new_margin); return -EINVAL; } soft_margin = new_margin; - printk(KERN_DEBUG - "hpwdt: New timer passed in is %d seconds.\n", - new_margin); + pr_debug("New timer passed in is %d seconds\n", new_margin); reload = SECS_TO_TICKS(soft_margin); return 0; @@ -490,7 +486,7 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) goto out; spin_lock_irqsave(&rom_lock, rom_pl); - if (!die_nmi_called && !is_icru) + if (!die_nmi_called && !is_icru && !is_uefi) asminline_call(&cmn_regs, cru_rom_addr); die_nmi_called = 1; spin_unlock_irqrestore(&rom_lock, rom_pl); @@ -498,14 +494,19 @@ static int hpwdt_pretimeout(unsigned int ulReason, struct pt_regs *regs) if (allow_kdump) hpwdt_stop(); - if (!is_icru) { + if (!is_icru && !is_uefi) { if (cmn_regs.u1.ral == 0) { panic("An NMI occurred, " "but unable to determine source.\n"); } } - panic("An NMI occurred, please see the Integrated " - "Management Log for details.\n"); + panic("An NMI occurred. Depending on your system the reason " + "for the NMI is logged in any one of the following " + "resources:\n" + "1. Integrated Management Log (IML)\n" + "2. OA Syslog\n" + "3. OA Forward Progress Log\n" + "4. iLO Event Log"); out: return NMI_DONE; @@ -534,8 +535,7 @@ static int hpwdt_release(struct inode *inode, struct file *file) if (expect_release == 42) { hpwdt_stop(); } else { - printk(KERN_CRIT - "hpwdt: Unexpected close, not stopping watchdog!\n"); + pr_crit("Unexpected close, not stopping watchdog!\n"); hpwdt_ping(); } @@ -654,7 +654,7 @@ static struct miscdevice hpwdt_miscdev = { #ifdef CONFIG_HPWDT_NMI_DECODING #ifdef CONFIG_X86_LOCAL_APIC -static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +static void hpwdt_check_nmi_decoding(struct pci_dev *dev) { /* * If nmi_watchdog is turned off then we can turn on @@ -663,7 +663,7 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) hpwdt_nmi_decoding = 1; } #else -static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +static void hpwdt_check_nmi_decoding(struct pci_dev *dev) { dev_warn(&dev->dev, "NMI decoding is disabled. " "Your kernel does not support a NMI Watchdog.\n"); @@ -678,7 +678,7 @@ static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) * This check is independent of architecture and needs to be made for * any ProLiant system. */ -static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy) +static void dmi_find_icru(const struct dmi_header *dm, void *dummy) { struct smbios_proliant_info *smbios_proliant_ptr; @@ -686,10 +686,12 @@ static void __devinit dmi_find_icru(const struct dmi_header *dm, void *dummy) smbios_proliant_ptr = (struct smbios_proliant_info *) dm; if (smbios_proliant_ptr->misc_features & 0x01) is_icru = 1; + if (smbios_proliant_ptr->misc_features & 0x408) + is_uefi = 1; } } -static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) +static int hpwdt_init_nmi_decoding(struct pci_dev *dev) { int retval; @@ -704,7 +706,7 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) * the old cru detect code. */ dmi_walk(dmi_find_icru, NULL); - if (!is_icru) { + if (!is_icru && !is_uefi) { /* * We need to map the ROM to get the CRU service. @@ -729,42 +731,51 @@ static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) } /* - * 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. + * Only one function can register for NMI_UNKNOWN */ - retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, - (priority) ? NMI_FLAG_FIRST : 0, - "hpwdt"); - if (retval != 0) { - dev_warn(&dev->dev, - "Unable to register a die notifier (err=%d).\n", - retval); - if (cru_rom_addr) - iounmap(cru_rom_addr); - } + retval = register_nmi_handler(NMI_UNKNOWN, hpwdt_pretimeout, 0, "hpwdt"); + if (retval) + goto error; + retval = register_nmi_handler(NMI_SERR, hpwdt_pretimeout, 0, "hpwdt"); + if (retval) + goto error1; + retval = register_nmi_handler(NMI_IO_CHECK, hpwdt_pretimeout, 0, "hpwdt"); + if (retval) + goto error2; dev_info(&dev->dev, "HP Watchdog Timer Driver: NMI decoding initialized" - ", allow kernel dump: %s (default = 0/OFF)" - ", priority: %s (default = 0/LAST).\n", - (allow_kdump == 0) ? "OFF" : "ON", - (priority == 0) ? "LAST" : "FIRST"); + ", allow kernel dump: %s (default = 0/OFF)\n", + (allow_kdump == 0) ? "OFF" : "ON"); return 0; + +error2: + unregister_nmi_handler(NMI_SERR, "hpwdt"); +error1: + unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); +error: + dev_warn(&dev->dev, + "Unable to register a die notifier (err=%d).\n", + retval); + if (cru_rom_addr) + iounmap(cru_rom_addr); + return retval; } static void hpwdt_exit_nmi_decoding(void) { unregister_nmi_handler(NMI_UNKNOWN, "hpwdt"); + unregister_nmi_handler(NMI_SERR, "hpwdt"); + unregister_nmi_handler(NMI_IO_CHECK, "hpwdt"); if (cru_rom_addr) iounmap(cru_rom_addr); } #else /* !CONFIG_HPWDT_NMI_DECODING */ -static void __devinit hpwdt_check_nmi_decoding(struct pci_dev *dev) +static void hpwdt_check_nmi_decoding(struct pci_dev *dev) { } -static int __devinit hpwdt_init_nmi_decoding(struct pci_dev *dev) +static int hpwdt_init_nmi_decoding(struct pci_dev *dev) { return 0; } @@ -774,7 +785,7 @@ static void hpwdt_exit_nmi_decoding(void) } #endif /* CONFIG_HPWDT_NMI_DECODING */ -static int __devinit hpwdt_init_one(struct pci_dev *dev, +static int hpwdt_init_one(struct pci_dev *dev, const struct pci_device_id *ent) { int retval; @@ -795,6 +806,12 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, return -ENODEV; } + /* + * Ignore all auxilary iLO devices with the following PCI ID + */ + if (dev->subsystem_device == 0x1979) + return -ENODEV; + if (pci_enable_device(dev)) { dev_warn(&dev->dev, "Not possible to enable PCI Device: 0x%x:0x%x.\n", @@ -812,6 +829,9 @@ static int __devinit hpwdt_init_one(struct pci_dev *dev, hpwdt_timer_reg = pci_mem_addr + 0x70; hpwdt_timer_con = pci_mem_addr + 0x72; + /* Make sure that timer is disabled until /dev/watchdog is opened */ + hpwdt_stop(); + /* Make sure that we have a valid soft_margin */ if (hpwdt_change_timer(soft_margin)) hpwdt_change_timer(DEFAULT_MARGIN); @@ -843,7 +863,7 @@ error_pci_iomap: return retval; } -static void __devexit hpwdt_exit(struct pci_dev *dev) +static void hpwdt_exit(struct pci_dev *dev) { if (!nowayout) hpwdt_stop(); @@ -858,40 +878,24 @@ static struct pci_driver hpwdt_driver = { .name = "hpwdt", .id_table = hpwdt_devices, .probe = hpwdt_init_one, - .remove = __devexit_p(hpwdt_exit), + .remove = hpwdt_exit, }; -static void __exit hpwdt_cleanup(void) -{ - pci_unregister_driver(&hpwdt_driver); -} - -static int __init hpwdt_init(void) -{ - return pci_register_driver(&hpwdt_driver); -} - MODULE_AUTHOR("Tom Mingarelli"); MODULE_DESCRIPTION("hp watchdog driver"); MODULE_LICENSE("GPL"); MODULE_VERSION(HPWDT_VERSION); -MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); module_param(soft_margin, int, 0); MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds"); -module_param(nowayout, int, 0); +module_param(nowayout, bool, 0); MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); #ifdef CONFIG_HPWDT_NMI_DECODING module_param(allow_kdump, int, 0); MODULE_PARM_DESC(allow_kdump, "Start a kernel dump after NMI occurs"); - -module_param(priority, int, 0); -MODULE_PARM_DESC(priority, "The hpwdt driver handles NMIs first or last" - " (default = 0/Last)\n"); #endif /* !CONFIG_HPWDT_NMI_DECODING */ -module_init(hpwdt_init); -module_exit(hpwdt_cleanup); +module_pci_driver(hpwdt_driver); |
