GIT fb8f7ba077b5c665432082ab205bcd2cb01f6a3c git+ssh://master.kernel.org/pub/scm/linux/kernel/git/wim/linux-2.6-watchdog-mm.git commit Author: Alexey Dobriyan Date: Sat Mar 24 15:58:12 2007 +0300 [WATCHDOG] Semi-typical watchdog bug re early misc_register() It seems that some watchdog drivers are doing following mistake: rv = misc_register(); if (rv < 0) return rv; rv = request_region(); if (rv < 0) { misc_deregister(); return rv; } But, right after misc_register() returns, misc device can be opened and ioctls interacting with hardware issued, and driver can do outb() to port it doesn't own yet, because request_region() is still pending. Here is my patch, compile-tested only. Signed-off-by: Alexey Dobriyan Signed-off-by: Wim Van Sebroeck commit 0e94f2ee0d1947ba6c2c00c3e971ff93ce8edec1 Author: Vlad Drukker Date: Sun Mar 25 17:34:39 2007 +0200 [WATCHDOG] add support for the w83627thf chipset. Added support for W83627THF, watchdog chip. Signed-off-by: Vlad Drukker Signed-off-by: Wim Van Sebroeck drivers/char/watchdog/cpu5wdt.c | 14 +++++++------- drivers/char/watchdog/eurotechwdt.c | 22 +++++++++++----------- drivers/char/watchdog/ibmasr.c | 11 +++++------ drivers/char/watchdog/machzwd.c | 18 +++++++++--------- drivers/char/watchdog/sbc8360.c | 28 ++++++++++++++-------------- drivers/char/watchdog/w83627hf_wdt.c | 23 ++++++++++++++++++----- 6 files changed, 64 insertions(+), 52 deletions(-) diff --git a/drivers/char/watchdog/cpu5wdt.c b/drivers/char/watchdog/cpu5wdt.c index bcd7e36..d0d45a8 100644 --- a/drivers/char/watchdog/cpu5wdt.c +++ b/drivers/char/watchdog/cpu5wdt.c @@ -220,17 +220,17 @@ static int __devinit cpu5wdt_init(void) if ( verbose ) printk(KERN_DEBUG PFX "port=0x%x, verbose=%i\n", port, verbose); - if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) { - printk(KERN_ERR PFX "misc_register failed\n"); - goto no_misc; - } - if ( !request_region(port, CPU5WDT_EXTENT, PFX) ) { printk(KERN_ERR PFX "request_region failed\n"); err = -EBUSY; goto no_port; } + if ( (err = misc_register(&cpu5wdt_misc)) < 0 ) { + printk(KERN_ERR PFX "misc_register failed\n"); + goto no_misc; + } + /* watchdog reboot? */ val = inb(port + CPU5WDT_STATUS_REG); val = (val >> 2) & 1; @@ -250,9 +250,9 @@ static int __devinit cpu5wdt_init(void) return 0; -no_port: - misc_deregister(&cpu5wdt_misc); no_misc: + release_region(port, CPU5WDT_EXTENT); +no_port: return err; } diff --git a/drivers/char/watchdog/eurotechwdt.c b/drivers/char/watchdog/eurotechwdt.c index f70387f..b070324 100644 --- a/drivers/char/watchdog/eurotechwdt.c +++ b/drivers/char/watchdog/eurotechwdt.c @@ -413,17 +413,10 @@ static int __init eurwdt_init(void) { int ret; - ret = misc_register(&eurwdt_miscdev); - if (ret) { - printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", - WATCHDOG_MINOR); - goto out; - } - ret = request_irq(irq, eurwdt_interrupt, IRQF_DISABLED, "eurwdt", NULL); if(ret) { printk(KERN_ERR "eurwdt: IRQ %d is not free.\n", irq); - goto outmisc; + goto out; } if (!request_region(io, 2, "eurwdt")) { @@ -438,6 +431,13 @@ static int __init eurwdt_init(void) goto outreg; } + ret = misc_register(&eurwdt_miscdev); + if (ret) { + printk(KERN_ERR "eurwdt: can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto outreboot; + } + eurwdt_unlock_chip(); ret = 0; @@ -448,14 +448,14 @@ static int __init eurwdt_init(void) out: return ret; +outreboot: + unregister_reboot_notifier(&eurwdt_notifier); + outreg: release_region(io, 2); outirq: free_irq(irq, NULL); - -outmisc: - misc_deregister(&eurwdt_miscdev); goto out; } diff --git a/drivers/char/watchdog/ibmasr.c b/drivers/char/watchdog/ibmasr.c index 8195f50..94155f6 100644 --- a/drivers/char/watchdog/ibmasr.c +++ b/drivers/char/watchdog/ibmasr.c @@ -367,18 +367,17 @@ static int __init ibmasr_init(void) if (!asr_type) return -ENODEV; + rc = asr_get_base_address(); + if (rc) + return rc; + rc = misc_register(&asr_miscdev); if (rc < 0) { + release_region(asr_base, asr_length); printk(KERN_ERR PFX "failed to register misc device\n"); return rc; } - rc = asr_get_base_address(); - if (rc) { - misc_deregister(&asr_miscdev); - return rc; - } - return 0; } diff --git a/drivers/char/watchdog/machzwd.c b/drivers/char/watchdog/machzwd.c index 76c7fa3..a0d2716 100644 --- a/drivers/char/watchdog/machzwd.c +++ b/drivers/char/watchdog/machzwd.c @@ -440,13 +440,6 @@ static int __init zf_init(void) spin_lock_init(&zf_lock); spin_lock_init(&zf_port_lock); - ret = misc_register(&zf_miscdev); - if (ret){ - printk(KERN_ERR "can't misc_register on minor=%d\n", - WATCHDOG_MINOR); - goto out; - } - if(!request_region(ZF_IOBASE, 3, "MachZ ZFL WDT")){ printk(KERN_ERR "cannot reserve I/O ports at %d\n", ZF_IOBASE); @@ -461,16 +454,23 @@ static int __init zf_init(void) goto no_reboot; } + ret = misc_register(&zf_miscdev); + if (ret){ + printk(KERN_ERR "can't misc_register on minor=%d\n", + WATCHDOG_MINOR); + goto no_misc; + } + zf_set_status(0); zf_set_control(0); return 0; +no_misc: + unregister_reboot_notifier(&zf_notifier); no_reboot: release_region(ZF_IOBASE, 3); no_region: - misc_deregister(&zf_miscdev); -out: return ret; } diff --git a/drivers/char/watchdog/sbc8360.c b/drivers/char/watchdog/sbc8360.c index 67ae426..285d852 100644 --- a/drivers/char/watchdog/sbc8360.c +++ b/drivers/char/watchdog/sbc8360.c @@ -333,18 +333,17 @@ static int __init sbc8360_init(void) int res; unsigned long int mseconds = 60000; - spin_lock_init(&sbc8360_lock); - res = misc_register(&sbc8360_miscdev); - if (res) { - printk(KERN_ERR PFX "failed to register misc device\n"); - goto out_nomisc; + if (timeout < 0 || timeout > 63) { + printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); + res = -EINVAL; + goto out; } if (!request_region(SBC8360_ENABLE, 1, "SBC8360")) { printk(KERN_ERR PFX "ENABLE method I/O %X is not available.\n", SBC8360_ENABLE); res = -EIO; - goto out_noenablereg; + goto out; } if (!request_region(SBC8360_BASETIME, 1, "SBC8360")) { printk(KERN_ERR PFX @@ -360,10 +359,11 @@ static int __init sbc8360_init(void) goto out_noreboot; } - if (timeout < 0 || timeout > 63) { - printk(KERN_ERR PFX "Invalid timeout index (must be 0-63).\n"); - res = -EINVAL; - goto out_noreboot; + spin_lock_init(&sbc8360_lock); + res = misc_register(&sbc8360_miscdev); + if (res) { + printk(KERN_ERR PFX "failed to register misc device\n"); + goto out_nomisc; } wd_margin = wd_times[timeout][0]; @@ -383,13 +383,13 @@ static int __init sbc8360_init(void) return 0; + out_nomisc: + unregister_reboot_notifier(&sbc8360_notifier); out_noreboot: - release_region(SBC8360_ENABLE, 1); release_region(SBC8360_BASETIME, 1); - out_noenablereg: out_nobasetimereg: - misc_deregister(&sbc8360_miscdev); - out_nomisc: + release_region(SBC8360_ENABLE, 1); + out: return res; } diff --git a/drivers/char/watchdog/w83627hf_wdt.c b/drivers/char/watchdog/w83627hf_wdt.c index 337ee42..b46e7f4 100644 --- a/drivers/char/watchdog/w83627hf_wdt.c +++ b/drivers/char/watchdog/w83627hf_wdt.c @@ -1,5 +1,8 @@ /* - * w83627hf WDT driver + * w83627hf/thf WDT driver + * + * (c) Copyright 2007 Vlad Drukker + * added support for W83627THF. * * (c) Copyright 2003 Pádraig Brady * @@ -39,7 +42,7 @@ #include #include #include -#define WATCHDOG_NAME "w83627hf WDT" +#define WATCHDOG_NAME "w83627hf/thf WDT" #define PFX WATCHDOG_NAME ": " #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ @@ -50,7 +53,7 @@ static spinlock_t io_lock; /* You must set this - there is no sane way to probe for this board. */ static int wdt_io = 0x2E; module_param(wdt_io, int, 0); -MODULE_PARM_DESC(wdt_io, "w83627hf WDT io port (default 0x2E)"); +MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ module_param(timeout, int, 0); @@ -71,9 +74,19 @@ #define WDT_EFDR (WDT_EFIR+1) /* Extende static void w83627hf_select_wd_register(void) { + unsigned char c; outb_p(0x87, WDT_EFER); /* Enter extended function mode */ outb_p(0x87, WDT_EFER); /* Again according to manual */ + outb(0x20, WDT_EFER); /* check chip version */ + c = inb(WDT_EFDR); + if (c == 0x82) { /* W83627THF */ + outb_p(0x2b, WDT_EFER); /* select GPIO3 */ + c = ((inb_p(WDT_EFDR) & 0xf7) | 0x04); /* select WDT0 */ + outb_p(0x2b, WDT_EFER); + outb_p(c, WDT_EFDR); /* set GPIO3 to WDT0 */ + } + outb_p(0x07, WDT_EFER); /* point to logical device number reg */ outb_p(0x08, WDT_EFDR); /* select logical device 8 (GPIO2) */ outb_p(0x30, WDT_EFER); /* select CR30 */ @@ -311,7 +324,7 @@ wdt_init(void) spin_lock_init(&io_lock); - printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF Super I/O chip initialising.\n"); + printk(KERN_INFO "WDT driver for the Winbond(TM) W83627HF/THF Super I/O chip initialising.\n"); if (wdt_set_heartbeat(timeout)) { wdt_set_heartbeat(WATCHDOG_TIMEOUT); @@ -367,5 +380,5 @@ module_exit(wdt_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Pádraig Brady "); -MODULE_DESCRIPTION("w83627hf WDT driver"); +MODULE_DESCRIPTION("w83627hf/thf WDT driver"); MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);