Commit a0cadc2777a71b1fde62e6417284b38e52128e88
Exists in
master
and in
7 other branches
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: iTCO_wdt.c: remove extra pci_dev_put()'s from init code watchdog: add support for Broadcom BCM63xx built-in watchdog watchdog: f71808e_wdt: add support for the F71889FG watchdog: MachZ: fix debug macro watchdog: it8712f_wdt: Add module parameter for alternative reset sources watchdog: it8712f_wdt: Add comments for config/control register names watchdog: it87_wdt: Add support for watchdogs with 8b timers watchdog: it87_wdt: Add support for IT8720F watchdog watchdog: Use static const char * const where possible watchdog: iTCO_wdt: Cleanup warning messages watchdog: iTCO_wdt: TCO Watchdog patch for Intel Patsburg DeviceIDs
Showing 8 changed files Side-by-side Diff
drivers/watchdog/Kconfig
... | ... | @@ -409,11 +409,11 @@ |
409 | 409 | Most people will say N. |
410 | 410 | |
411 | 411 | config F71808E_WDT |
412 | - tristate "Fintek F71808E and F71882FG Watchdog" | |
412 | + tristate "Fintek F71808E, F71882FG and F71889FG Watchdog" | |
413 | 413 | depends on X86 && EXPERIMENTAL |
414 | 414 | help |
415 | 415 | This is the driver for the hardware watchdog on the Fintek |
416 | - F71808E and F71882FG Super I/O controllers. | |
416 | + F71808E, F71882FG and F71889FG Super I/O controllers. | |
417 | 417 | |
418 | 418 | You can compile this driver directly into the kernel, or use |
419 | 419 | it as a module. The module will be called f71808e_wdt. |
... | ... | @@ -565,10 +565,11 @@ |
565 | 565 | tristate "IT87 Watchdog Timer" |
566 | 566 | depends on X86 && EXPERIMENTAL |
567 | 567 | ---help--- |
568 | - This is the driver for the hardware watchdog on the ITE IT8716, | |
569 | - IT8718, IT8726, IT8712(Version J,K) Super I/O chips. This watchdog | |
570 | - simply watches your kernel to make sure it doesn't freeze, and if | |
571 | - it does, it reboots your computer after a certain amount of time. | |
568 | + This is the driver for the hardware watchdog on the ITE IT8702, | |
569 | + IT8712, IT8716, IT8718, IT8720, IT8726, IT8712 Super I/O chips. | |
570 | + This watchdog simply watches your kernel to make sure it doesn't | |
571 | + freeze, and if it does, it reboots your computer after a certain | |
572 | + amount of time. | |
572 | 573 | |
573 | 574 | To compile this driver as a module, choose M here: the module will |
574 | 575 | be called it87_wdt. |
... | ... | @@ -915,6 +916,16 @@ |
915 | 916 | When userspace has /dev/watchdog open, no poking is done |
916 | 917 | from the first interrupt, it is then only poked when the |
917 | 918 | device is written. |
919 | + | |
920 | +config BCM63XX_WDT | |
921 | + tristate "Broadcom BCM63xx hardware watchdog" | |
922 | + depends on BCM63XX | |
923 | + help | |
924 | + Watchdog driver for the built in watchdog hardware in Broadcom | |
925 | + BCM63xx SoC. | |
926 | + | |
927 | + To compile this driver as a loadable module, choose M here. | |
928 | + The module will be called bcm63xx_wdt. | |
918 | 929 | |
919 | 930 | # PARISC Architecture |
920 | 931 |
drivers/watchdog/Makefile
... | ... | @@ -109,6 +109,7 @@ |
109 | 109 | |
110 | 110 | # MIPS Architecture |
111 | 111 | obj-$(CONFIG_BCM47XX_WDT) += bcm47xx_wdt.o |
112 | +obj-$(CONFIG_BCM63XX_WDT) += bcm63xx_wdt.o | |
112 | 113 | obj-$(CONFIG_RC32434_WDT) += rc32434_wdt.o |
113 | 114 | obj-$(CONFIG_INDYDOG) += indydog.o |
114 | 115 | obj-$(CONFIG_WDT_MTX1) += mtx-1_wdt.o |
drivers/watchdog/bcm63xx_wdt.c
1 | +/* | |
2 | + * Broadcom BCM63xx SoC watchdog driver | |
3 | + * | |
4 | + * Copyright (C) 2007, Miguel Gaio <miguel.gaio@efixo.com> | |
5 | + * Copyright (C) 2008, Florian Fainelli <florian@openwrt.org> | |
6 | + * | |
7 | + * This program is free software; you can redistribute it and/or | |
8 | + * modify it under the terms of the GNU General Public License | |
9 | + * as published by the Free Software Foundation; either version | |
10 | + * 2 of the License, or (at your option) any later version. | |
11 | + */ | |
12 | + | |
13 | +#include <linux/bitops.h> | |
14 | +#include <linux/errno.h> | |
15 | +#include <linux/fs.h> | |
16 | +#include <linux/init.h> | |
17 | +#include <linux/kernel.h> | |
18 | +#include <linux/miscdevice.h> | |
19 | +#include <linux/module.h> | |
20 | +#include <linux/moduleparam.h> | |
21 | +#include <linux/reboot.h> | |
22 | +#include <linux/types.h> | |
23 | +#include <linux/uaccess.h> | |
24 | +#include <linux/watchdog.h> | |
25 | +#include <linux/timer.h> | |
26 | +#include <linux/jiffies.h> | |
27 | +#include <linux/interrupt.h> | |
28 | +#include <linux/ptrace.h> | |
29 | +#include <linux/resource.h> | |
30 | +#include <linux/platform_device.h> | |
31 | + | |
32 | +#include <bcm63xx_cpu.h> | |
33 | +#include <bcm63xx_io.h> | |
34 | +#include <bcm63xx_regs.h> | |
35 | +#include <bcm63xx_timer.h> | |
36 | + | |
37 | +#define PFX KBUILD_MODNAME | |
38 | + | |
39 | +#define WDT_HZ 50000000 /* Fclk */ | |
40 | +#define WDT_DEFAULT_TIME 30 /* seconds */ | |
41 | +#define WDT_MAX_TIME 256 /* seconds */ | |
42 | + | |
43 | +static struct { | |
44 | + void __iomem *regs; | |
45 | + struct timer_list timer; | |
46 | + int default_ticks; | |
47 | + unsigned long inuse; | |
48 | + atomic_t ticks; | |
49 | +} bcm63xx_wdt_device; | |
50 | + | |
51 | +static int expect_close; | |
52 | + | |
53 | +static int wdt_time = WDT_DEFAULT_TIME; | |
54 | +static int nowayout = WATCHDOG_NOWAYOUT; | |
55 | +module_param(nowayout, int, 0); | |
56 | +MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | |
57 | + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | |
58 | + | |
59 | +/* HW functions */ | |
60 | +static void bcm63xx_wdt_hw_start(void) | |
61 | +{ | |
62 | + bcm_writel(0xfffffffe, bcm63xx_wdt_device.regs + WDT_DEFVAL_REG); | |
63 | + bcm_writel(WDT_START_1, bcm63xx_wdt_device.regs + WDT_CTL_REG); | |
64 | + bcm_writel(WDT_START_2, bcm63xx_wdt_device.regs + WDT_CTL_REG); | |
65 | +} | |
66 | + | |
67 | +static void bcm63xx_wdt_hw_stop(void) | |
68 | +{ | |
69 | + bcm_writel(WDT_STOP_1, bcm63xx_wdt_device.regs + WDT_CTL_REG); | |
70 | + bcm_writel(WDT_STOP_2, bcm63xx_wdt_device.regs + WDT_CTL_REG); | |
71 | +} | |
72 | + | |
73 | +static void bcm63xx_wdt_isr(void *data) | |
74 | +{ | |
75 | + struct pt_regs *regs = get_irq_regs(); | |
76 | + | |
77 | + die(PFX " fire", regs); | |
78 | +} | |
79 | + | |
80 | +static void bcm63xx_timer_tick(unsigned long unused) | |
81 | +{ | |
82 | + if (!atomic_dec_and_test(&bcm63xx_wdt_device.ticks)) { | |
83 | + bcm63xx_wdt_hw_start(); | |
84 | + mod_timer(&bcm63xx_wdt_device.timer, jiffies + HZ); | |
85 | + } else | |
86 | + printk(KERN_CRIT PFX ": watchdog will restart system\n"); | |
87 | +} | |
88 | + | |
89 | +static void bcm63xx_wdt_pet(void) | |
90 | +{ | |
91 | + atomic_set(&bcm63xx_wdt_device.ticks, wdt_time); | |
92 | +} | |
93 | + | |
94 | +static void bcm63xx_wdt_start(void) | |
95 | +{ | |
96 | + bcm63xx_wdt_pet(); | |
97 | + bcm63xx_timer_tick(0); | |
98 | +} | |
99 | + | |
100 | +static void bcm63xx_wdt_pause(void) | |
101 | +{ | |
102 | + del_timer_sync(&bcm63xx_wdt_device.timer); | |
103 | + bcm63xx_wdt_hw_stop(); | |
104 | +} | |
105 | + | |
106 | +static int bcm63xx_wdt_settimeout(int new_time) | |
107 | +{ | |
108 | + if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) | |
109 | + return -EINVAL; | |
110 | + | |
111 | + wdt_time = new_time; | |
112 | + | |
113 | + return 0; | |
114 | +} | |
115 | + | |
116 | +static int bcm63xx_wdt_open(struct inode *inode, struct file *file) | |
117 | +{ | |
118 | + if (test_and_set_bit(0, &bcm63xx_wdt_device.inuse)) | |
119 | + return -EBUSY; | |
120 | + | |
121 | + bcm63xx_wdt_start(); | |
122 | + return nonseekable_open(inode, file); | |
123 | +} | |
124 | + | |
125 | +static int bcm63xx_wdt_release(struct inode *inode, struct file *file) | |
126 | +{ | |
127 | + if (expect_close == 42) | |
128 | + bcm63xx_wdt_pause(); | |
129 | + else { | |
130 | + printk(KERN_CRIT PFX | |
131 | + ": Unexpected close, not stopping watchdog!\n"); | |
132 | + bcm63xx_wdt_start(); | |
133 | + } | |
134 | + clear_bit(0, &bcm63xx_wdt_device.inuse); | |
135 | + expect_close = 0; | |
136 | + return 0; | |
137 | +} | |
138 | + | |
139 | +static ssize_t bcm63xx_wdt_write(struct file *file, const char *data, | |
140 | + size_t len, loff_t *ppos) | |
141 | +{ | |
142 | + if (len) { | |
143 | + if (!nowayout) { | |
144 | + size_t i; | |
145 | + | |
146 | + /* In case it was set long ago */ | |
147 | + expect_close = 0; | |
148 | + | |
149 | + for (i = 0; i != len; i++) { | |
150 | + char c; | |
151 | + if (get_user(c, data + i)) | |
152 | + return -EFAULT; | |
153 | + if (c == 'V') | |
154 | + expect_close = 42; | |
155 | + } | |
156 | + } | |
157 | + bcm63xx_wdt_pet(); | |
158 | + } | |
159 | + return len; | |
160 | +} | |
161 | + | |
162 | +static struct watchdog_info bcm63xx_wdt_info = { | |
163 | + .identity = PFX, | |
164 | + .options = WDIOF_SETTIMEOUT | | |
165 | + WDIOF_KEEPALIVEPING | | |
166 | + WDIOF_MAGICCLOSE, | |
167 | +}; | |
168 | + | |
169 | + | |
170 | +static long bcm63xx_wdt_ioctl(struct file *file, unsigned int cmd, | |
171 | + unsigned long arg) | |
172 | +{ | |
173 | + void __user *argp = (void __user *)arg; | |
174 | + int __user *p = argp; | |
175 | + int new_value, retval = -EINVAL; | |
176 | + | |
177 | + switch (cmd) { | |
178 | + case WDIOC_GETSUPPORT: | |
179 | + return copy_to_user(argp, &bcm63xx_wdt_info, | |
180 | + sizeof(bcm63xx_wdt_info)) ? -EFAULT : 0; | |
181 | + | |
182 | + case WDIOC_GETSTATUS: | |
183 | + case WDIOC_GETBOOTSTATUS: | |
184 | + return put_user(0, p); | |
185 | + | |
186 | + case WDIOC_SETOPTIONS: | |
187 | + if (get_user(new_value, p)) | |
188 | + return -EFAULT; | |
189 | + | |
190 | + if (new_value & WDIOS_DISABLECARD) { | |
191 | + bcm63xx_wdt_pause(); | |
192 | + retval = 0; | |
193 | + } | |
194 | + if (new_value & WDIOS_ENABLECARD) { | |
195 | + bcm63xx_wdt_start(); | |
196 | + retval = 0; | |
197 | + } | |
198 | + | |
199 | + return retval; | |
200 | + | |
201 | + case WDIOC_KEEPALIVE: | |
202 | + bcm63xx_wdt_pet(); | |
203 | + return 0; | |
204 | + | |
205 | + case WDIOC_SETTIMEOUT: | |
206 | + if (get_user(new_value, p)) | |
207 | + return -EFAULT; | |
208 | + | |
209 | + if (bcm63xx_wdt_settimeout(new_value)) | |
210 | + return -EINVAL; | |
211 | + | |
212 | + bcm63xx_wdt_pet(); | |
213 | + | |
214 | + case WDIOC_GETTIMEOUT: | |
215 | + return put_user(wdt_time, p); | |
216 | + | |
217 | + default: | |
218 | + return -ENOTTY; | |
219 | + | |
220 | + } | |
221 | +} | |
222 | + | |
223 | +static int bcm63xx_wdt_notify_sys(struct notifier_block *this, | |
224 | + unsigned long code, void *unused) | |
225 | +{ | |
226 | + if (code == SYS_DOWN || code == SYS_HALT) | |
227 | + bcm63xx_wdt_pause(); | |
228 | + return NOTIFY_DONE; | |
229 | +} | |
230 | + | |
231 | +static const struct file_operations bcm63xx_wdt_fops = { | |
232 | + .owner = THIS_MODULE, | |
233 | + .llseek = no_llseek, | |
234 | + .write = bcm63xx_wdt_write, | |
235 | + .unlocked_ioctl = bcm63xx_wdt_ioctl, | |
236 | + .open = bcm63xx_wdt_open, | |
237 | + .release = bcm63xx_wdt_release, | |
238 | +}; | |
239 | + | |
240 | +static struct miscdevice bcm63xx_wdt_miscdev = { | |
241 | + .minor = WATCHDOG_MINOR, | |
242 | + .name = "watchdog", | |
243 | + .fops = &bcm63xx_wdt_fops, | |
244 | +}; | |
245 | + | |
246 | +static struct notifier_block bcm63xx_wdt_notifier = { | |
247 | + .notifier_call = bcm63xx_wdt_notify_sys, | |
248 | +}; | |
249 | + | |
250 | + | |
251 | +static int bcm63xx_wdt_probe(struct platform_device *pdev) | |
252 | +{ | |
253 | + int ret; | |
254 | + struct resource *r; | |
255 | + | |
256 | + setup_timer(&bcm63xx_wdt_device.timer, bcm63xx_timer_tick, 0L); | |
257 | + | |
258 | + r = platform_get_resource(pdev, IORESOURCE_MEM, 0); | |
259 | + if (!r) { | |
260 | + dev_err(&pdev->dev, "failed to get resources\n"); | |
261 | + return -ENODEV; | |
262 | + } | |
263 | + | |
264 | + bcm63xx_wdt_device.regs = ioremap_nocache(r->start, r->end - r->start); | |
265 | + if (!bcm63xx_wdt_device.regs) { | |
266 | + dev_err(&pdev->dev, "failed to remap I/O resources\n"); | |
267 | + return -ENXIO; | |
268 | + } | |
269 | + | |
270 | + ret = bcm63xx_timer_register(TIMER_WDT_ID, bcm63xx_wdt_isr, NULL); | |
271 | + if (ret < 0) { | |
272 | + dev_err(&pdev->dev, "failed to register wdt timer isr\n"); | |
273 | + goto unmap; | |
274 | + } | |
275 | + | |
276 | + if (bcm63xx_wdt_settimeout(wdt_time)) { | |
277 | + bcm63xx_wdt_settimeout(WDT_DEFAULT_TIME); | |
278 | + dev_info(&pdev->dev, | |
279 | + ": wdt_time value must be 1 <= wdt_time <= 256, using %d\n", | |
280 | + wdt_time); | |
281 | + } | |
282 | + | |
283 | + ret = register_reboot_notifier(&bcm63xx_wdt_notifier); | |
284 | + if (ret) { | |
285 | + dev_err(&pdev->dev, "failed to register reboot_notifier\n"); | |
286 | + goto unregister_timer; | |
287 | + } | |
288 | + | |
289 | + ret = misc_register(&bcm63xx_wdt_miscdev); | |
290 | + if (ret < 0) { | |
291 | + dev_err(&pdev->dev, "failed to register watchdog device\n"); | |
292 | + goto unregister_reboot_notifier; | |
293 | + } | |
294 | + | |
295 | + dev_info(&pdev->dev, " started, timer margin: %d sec\n", | |
296 | + WDT_DEFAULT_TIME); | |
297 | + | |
298 | + return 0; | |
299 | + | |
300 | +unregister_reboot_notifier: | |
301 | + unregister_reboot_notifier(&bcm63xx_wdt_notifier); | |
302 | +unregister_timer: | |
303 | + bcm63xx_timer_unregister(TIMER_WDT_ID); | |
304 | +unmap: | |
305 | + iounmap(bcm63xx_wdt_device.regs); | |
306 | + return ret; | |
307 | +} | |
308 | + | |
309 | +static int bcm63xx_wdt_remove(struct platform_device *pdev) | |
310 | +{ | |
311 | + if (!nowayout) | |
312 | + bcm63xx_wdt_pause(); | |
313 | + | |
314 | + misc_deregister(&bcm63xx_wdt_miscdev); | |
315 | + | |
316 | + iounmap(bcm63xx_wdt_device.regs); | |
317 | + | |
318 | + unregister_reboot_notifier(&bcm63xx_wdt_notifier); | |
319 | + bcm63xx_timer_unregister(TIMER_WDT_ID); | |
320 | + | |
321 | + return 0; | |
322 | +} | |
323 | + | |
324 | +static struct platform_driver bcm63xx_wdt = { | |
325 | + .probe = bcm63xx_wdt_probe, | |
326 | + .remove = bcm63xx_wdt_remove, | |
327 | + .driver = { | |
328 | + .name = "bcm63xx-wdt", | |
329 | + } | |
330 | +}; | |
331 | + | |
332 | +static int __init bcm63xx_wdt_init(void) | |
333 | +{ | |
334 | + return platform_driver_register(&bcm63xx_wdt); | |
335 | +} | |
336 | + | |
337 | +static void __exit bcm63xx_wdt_exit(void) | |
338 | +{ | |
339 | + platform_driver_unregister(&bcm63xx_wdt); | |
340 | +} | |
341 | + | |
342 | +module_init(bcm63xx_wdt_init); | |
343 | +module_exit(bcm63xx_wdt_exit); | |
344 | + | |
345 | +MODULE_AUTHOR("Miguel Gaio <miguel.gaio@efixo.com>"); | |
346 | +MODULE_AUTHOR("Florian Fainelli <florian@openwrt.org>"); | |
347 | +MODULE_DESCRIPTION("Driver for the Broadcom BCM63xx SoC watchdog"); | |
348 | +MODULE_LICENSE("GPL"); | |
349 | +MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); | |
350 | +MODULE_ALIAS("platform:bcm63xx-wdt"); |
drivers/watchdog/f71808e_wdt.c
... | ... | @@ -308,6 +308,12 @@ |
308 | 308 | superio_set_bit(watchdog.sioaddr, 0x29, 1); |
309 | 309 | break; |
310 | 310 | |
311 | + case f71889fg: | |
312 | + /* set pin 40 to WDTRST# */ | |
313 | + superio_outb(watchdog.sioaddr, 0x2b, | |
314 | + superio_inb(watchdog.sioaddr, 0x2b) & 0xcf); | |
315 | + break; | |
316 | + | |
311 | 317 | default: |
312 | 318 | /* |
313 | 319 | * 'default' label to shut up the compiler and catch |
314 | 320 | |
... | ... | @@ -708,8 +714,10 @@ |
708 | 714 | case SIO_F71882_ID: |
709 | 715 | watchdog.type = f71882fg; |
710 | 716 | break; |
711 | - case SIO_F71862_ID: | |
712 | 717 | case SIO_F71889_ID: |
718 | + watchdog.type = f71889fg; | |
719 | + break; | |
720 | + case SIO_F71862_ID: | |
713 | 721 | /* These have a watchdog, though it isn't implemented (yet). */ |
714 | 722 | err = -ENOSYS; |
715 | 723 | goto exit; |
drivers/watchdog/iTCO_wdt.c
... | ... | @@ -146,6 +146,7 @@ |
146 | 146 | TCO_CPT29, /* Cougar Point */ |
147 | 147 | TCO_CPT30, /* Cougar Point */ |
148 | 148 | TCO_CPT31, /* Cougar Point */ |
149 | + TCO_PBG, /* Patsburg */ | |
149 | 150 | }; |
150 | 151 | |
151 | 152 | static struct { |
... | ... | @@ -233,6 +234,7 @@ |
233 | 234 | {"Cougar Point", 2}, |
234 | 235 | {"Cougar Point", 2}, |
235 | 236 | {"Cougar Point", 2}, |
237 | + {"Patsburg", 2}, | |
236 | 238 | {NULL, 0} |
237 | 239 | }; |
238 | 240 | |
... | ... | @@ -348,6 +350,7 @@ |
348 | 350 | { ITCO_PCI_DEVICE(0x1c5d, TCO_CPT29)}, |
349 | 351 | { ITCO_PCI_DEVICE(0x1c5e, TCO_CPT30)}, |
350 | 352 | { ITCO_PCI_DEVICE(0x1c5f, TCO_CPT31)}, |
353 | + { ITCO_PCI_DEVICE(0x1d40, TCO_PBG)}, | |
351 | 354 | { 0, }, /* End of list */ |
352 | 355 | }; |
353 | 356 | MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl); |
... | ... | @@ -374,7 +377,7 @@ |
374 | 377 | static struct { /* this is private data for the iTCO_wdt device */ |
375 | 378 | /* TCO version/generation */ |
376 | 379 | unsigned int iTCO_version; |
377 | - /* The cards ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ | |
380 | + /* The device's ACPIBASE address (TCOBASE = ACPIBASE+0x60) */ | |
378 | 381 | unsigned long ACPIBASE; |
379 | 382 | /* NO_REBOOT flag is Memory-Mapped GCS register bit 5 (TCO version 2)*/ |
380 | 383 | unsigned long __iomem *gcs; |
... | ... | @@ -467,7 +470,7 @@ |
467 | 470 | if (iTCO_wdt_unset_NO_REBOOT_bit()) { |
468 | 471 | spin_unlock(&iTCO_wdt_private.io_lock); |
469 | 472 | printk(KERN_ERR PFX "failed to reset NO_REBOOT flag, " |
470 | - "reboot disabled by hardware\n"); | |
473 | + "reboot disabled by hardware/BIOS\n"); | |
471 | 474 | return -EIO; |
472 | 475 | } |
473 | 476 | |
... | ... | @@ -781,8 +784,8 @@ |
781 | 784 | base_address &= 0x0000ff80; |
782 | 785 | if (base_address == 0x00000000) { |
783 | 786 | /* Something's wrong here, ACPIBASE has to be set */ |
784 | - printk(KERN_ERR PFX "failed to get TCOBASE address\n"); | |
785 | - pci_dev_put(pdev); | |
787 | + printk(KERN_ERR PFX "failed to get TCOBASE address, " | |
788 | + "device disabled by hardware/BIOS\n"); | |
786 | 789 | return -ENODEV; |
787 | 790 | } |
788 | 791 | iTCO_wdt_private.iTCO_version = |
... | ... | @@ -797,7 +800,8 @@ |
797 | 800 | if (iTCO_wdt_private.iTCO_version == 2) { |
798 | 801 | pci_read_config_dword(pdev, 0xf0, &base_address); |
799 | 802 | if ((base_address & 1) == 0) { |
800 | - printk(KERN_ERR PFX "RCBA is disabled by hardware\n"); | |
803 | + printk(KERN_ERR PFX "RCBA is disabled by hardware" | |
804 | + "/BIOS, device disabled\n"); | |
801 | 805 | ret = -ENODEV; |
802 | 806 | goto out; |
803 | 807 | } |
... | ... | @@ -808,7 +812,7 @@ |
808 | 812 | /* Check chipset's NO_REBOOT bit */ |
809 | 813 | if (iTCO_wdt_unset_NO_REBOOT_bit() && iTCO_vendor_check_noreboot_on()) { |
810 | 814 | printk(KERN_INFO PFX "unable to reset NO_REBOOT flag, " |
811 | - "platform may have disabled it\n"); | |
815 | + "device disabled by hardware/BIOS\n"); | |
812 | 816 | ret = -ENODEV; /* Cannot reset NO_REBOOT bit */ |
813 | 817 | goto out_unmap; |
814 | 818 | } |
... | ... | @@ -819,7 +823,8 @@ |
819 | 823 | /* The TCO logic uses the TCO_EN bit in the SMI_EN register */ |
820 | 824 | if (!request_region(SMI_EN, 4, "iTCO_wdt")) { |
821 | 825 | printk(KERN_ERR PFX |
822 | - "I/O address 0x%04lx already in use\n", SMI_EN); | |
826 | + "I/O address 0x%04lx already in use, " | |
827 | + "device disabled\n", SMI_EN); | |
823 | 828 | ret = -EIO; |
824 | 829 | goto out_unmap; |
825 | 830 | } |
... | ... | @@ -831,8 +836,8 @@ |
831 | 836 | /* The TCO I/O registers reside in a 32-byte range pointed to |
832 | 837 | by the TCOBASE value */ |
833 | 838 | if (!request_region(TCOBASE, 0x20, "iTCO_wdt")) { |
834 | - printk(KERN_ERR PFX "I/O address 0x%04lx already in use\n", | |
835 | - TCOBASE); | |
839 | + printk(KERN_ERR PFX "I/O address 0x%04lx already in use " | |
840 | + "device disabled\n", TCOBASE); | |
836 | 841 | ret = -EIO; |
837 | 842 | goto unreg_smi_en; |
838 | 843 | } |
... | ... | @@ -880,7 +885,6 @@ |
880 | 885 | if (iTCO_wdt_private.iTCO_version == 2) |
881 | 886 | iounmap(iTCO_wdt_private.gcs); |
882 | 887 | out: |
883 | - pci_dev_put(iTCO_wdt_private.pdev); | |
884 | 888 | iTCO_wdt_private.ACPIBASE = 0; |
885 | 889 | return ret; |
886 | 890 | } |
... | ... | @@ -921,7 +925,7 @@ |
921 | 925 | } |
922 | 926 | |
923 | 927 | if (!found) |
924 | - printk(KERN_INFO PFX "No card detected\n"); | |
928 | + printk(KERN_INFO PFX "No device detected.\n"); | |
925 | 929 | |
926 | 930 | return ret; |
927 | 931 | } |
drivers/watchdog/it8712f_wdt.c
... | ... | @@ -75,16 +75,24 @@ |
75 | 75 | #define WDT_CONFIG 0x72 /* WDT Register: Configuration */ |
76 | 76 | #define WDT_TIMEOUT 0x73 /* WDT Register: Timeout Value */ |
77 | 77 | |
78 | -#define WDT_RESET_GAME 0x10 | |
79 | -#define WDT_RESET_KBD 0x20 | |
80 | -#define WDT_RESET_MOUSE 0x40 | |
81 | -#define WDT_RESET_CIR 0x80 | |
78 | +#define WDT_RESET_GAME 0x10 /* Reset timer on read or write to game port */ | |
79 | +#define WDT_RESET_KBD 0x20 /* Reset timer on keyboard interrupt */ | |
80 | +#define WDT_RESET_MOUSE 0x40 /* Reset timer on mouse interrupt */ | |
81 | +#define WDT_RESET_CIR 0x80 /* Reset timer on consumer IR interrupt */ | |
82 | 82 | |
83 | 83 | #define WDT_UNIT_SEC 0x80 /* If 0 in MINUTES */ |
84 | 84 | |
85 | -#define WDT_OUT_PWROK 0x10 | |
86 | -#define WDT_OUT_KRST 0x40 | |
85 | +#define WDT_OUT_PWROK 0x10 /* Pulse PWROK on timeout */ | |
86 | +#define WDT_OUT_KRST 0x40 /* Pulse reset on timeout */ | |
87 | 87 | |
88 | +static int wdt_control_reg = WDT_RESET_GAME; | |
89 | +module_param(wdt_control_reg, int, 0); | |
90 | +MODULE_PARM_DESC(wdt_control_reg, "Value to write to watchdog control " | |
91 | + "register. The default WDT_RESET_GAME resets the timer on " | |
92 | + "game port reads that this driver generates. You can also " | |
93 | + "use KBD, MOUSE or CIR if you have some external way to " | |
94 | + "generate those interrupts."); | |
95 | + | |
88 | 96 | static int superio_inb(int reg) |
89 | 97 | { |
90 | 98 | outb(reg, REG); |
... | ... | @@ -131,7 +139,8 @@ |
131 | 139 | |
132 | 140 | static inline void it8712f_wdt_ping(void) |
133 | 141 | { |
134 | - inb(address); | |
142 | + if (wdt_control_reg & WDT_RESET_GAME) | |
143 | + inb(address); | |
135 | 144 | } |
136 | 145 | |
137 | 146 | static void it8712f_wdt_update_margin(void) |
... | ... | @@ -170,7 +179,7 @@ |
170 | 179 | superio_enter(); |
171 | 180 | superio_select(LDN_GPIO); |
172 | 181 | |
173 | - superio_outb(WDT_RESET_GAME, WDT_CONTROL); | |
182 | + superio_outb(wdt_control_reg, WDT_CONTROL); | |
174 | 183 | |
175 | 184 | it8712f_wdt_update_margin(); |
176 | 185 |
drivers/watchdog/it87_wdt.c
... | ... | @@ -12,7 +12,7 @@ |
12 | 12 | * http://www.ite.com.tw/ |
13 | 13 | * |
14 | 14 | * Support of the watchdog timers, which are available on |
15 | - * IT8716, IT8718, IT8726 and IT8712 (J,K version). | |
15 | + * IT8702, IT8712, IT8716, IT8718, IT8720 and IT8726. | |
16 | 16 | * |
17 | 17 | * This program is free software; you can redistribute it and/or |
18 | 18 | * modify it under the terms of the GNU General Public License |
... | ... | @@ -45,7 +45,7 @@ |
45 | 45 | |
46 | 46 | #include <asm/system.h> |
47 | 47 | |
48 | -#define WATCHDOG_VERSION "1.12" | |
48 | +#define WATCHDOG_VERSION "1.13" | |
49 | 49 | #define WATCHDOG_NAME "IT87 WDT" |
50 | 50 | #define PFX WATCHDOG_NAME ": " |
51 | 51 | #define DRIVER_VERSION WATCHDOG_NAME " driver, v" WATCHDOG_VERSION "\n" |
52 | 52 | |
... | ... | @@ -76,10 +76,12 @@ |
76 | 76 | |
77 | 77 | /* Chip Id numbers */ |
78 | 78 | #define NO_DEV_ID 0xffff |
79 | +#define IT8702_ID 0x8702 | |
79 | 80 | #define IT8705_ID 0x8705 |
80 | 81 | #define IT8712_ID 0x8712 |
81 | 82 | #define IT8716_ID 0x8716 |
82 | 83 | #define IT8718_ID 0x8718 |
84 | +#define IT8720_ID 0x8720 | |
83 | 85 | #define IT8726_ID 0x8726 /* the data sheet suggest wrongly 0x8716 */ |
84 | 86 | |
85 | 87 | /* GPIO Configuration Registers LDN=0x07 */ |
... | ... | @@ -92,7 +94,7 @@ |
92 | 94 | #define WDT_CIRINT 0x80 |
93 | 95 | #define WDT_MOUSEINT 0x40 |
94 | 96 | #define WDT_KYBINT 0x20 |
95 | -#define WDT_GAMEPORT 0x10 /* not it8718 */ | |
97 | +#define WDT_GAMEPORT 0x10 /* not in it8718, it8720 */ | |
96 | 98 | #define WDT_FORCE 0x02 |
97 | 99 | #define WDT_ZERO 0x01 |
98 | 100 | |
... | ... | @@ -132,7 +134,7 @@ |
132 | 134 | #define WDTS_USE_GP 4 |
133 | 135 | #define WDTS_EXPECTED 5 |
134 | 136 | |
135 | -static unsigned int base, gpact, ciract; | |
137 | +static unsigned int base, gpact, ciract, max_units; | |
136 | 138 | static unsigned long wdt_status; |
137 | 139 | static DEFINE_SPINLOCK(spinlock); |
138 | 140 | |
... | ... | @@ -210,6 +212,33 @@ |
210 | 212 | outb(val, VAL); |
211 | 213 | } |
212 | 214 | |
215 | +/* Internal function, should be called after superio_select(GPIO) */ | |
216 | +static void wdt_update_timeout(void) | |
217 | +{ | |
218 | + unsigned char cfg = WDT_KRST | WDT_PWROK; | |
219 | + int tm = timeout; | |
220 | + | |
221 | + if (testmode) | |
222 | + cfg = 0; | |
223 | + | |
224 | + if (tm <= max_units) | |
225 | + cfg |= WDT_TOV1; | |
226 | + else | |
227 | + tm /= 60; | |
228 | + | |
229 | + superio_outb(cfg, WDTCFG); | |
230 | + superio_outb(tm, WDTVALLSB); | |
231 | + if (max_units > 255) | |
232 | + superio_outb(tm>>8, WDTVALMSB); | |
233 | +} | |
234 | + | |
235 | +static int wdt_round_time(int t) | |
236 | +{ | |
237 | + t += 59; | |
238 | + t -= t % 60; | |
239 | + return t; | |
240 | +} | |
241 | + | |
213 | 242 | /* watchdog timer handling */ |
214 | 243 | |
215 | 244 | static void wdt_keepalive(void) |
... | ... | @@ -234,12 +263,7 @@ |
234 | 263 | superio_outb(WDT_GAMEPORT, WDTCTRL); |
235 | 264 | else |
236 | 265 | superio_outb(WDT_CIRINT, WDTCTRL); |
237 | - if (!testmode) | |
238 | - superio_outb(WDT_TOV1 | WDT_KRST | WDT_PWROK, WDTCFG); | |
239 | - else | |
240 | - superio_outb(WDT_TOV1, WDTCFG); | |
241 | - superio_outb(timeout>>8, WDTVALMSB); | |
242 | - superio_outb(timeout, WDTVALLSB); | |
266 | + wdt_update_timeout(); | |
243 | 267 | |
244 | 268 | superio_exit(); |
245 | 269 | spin_unlock_irqrestore(&spinlock, flags); |
246 | 270 | |
... | ... | @@ -255,8 +279,9 @@ |
255 | 279 | superio_select(GPIO); |
256 | 280 | superio_outb(0x00, WDTCTRL); |
257 | 281 | superio_outb(WDT_TOV1, WDTCFG); |
258 | - superio_outb(0x00, WDTVALMSB); | |
259 | 282 | superio_outb(0x00, WDTVALLSB); |
283 | + if (max_units > 255) | |
284 | + superio_outb(0x00, WDTVALMSB); | |
260 | 285 | |
261 | 286 | superio_exit(); |
262 | 287 | spin_unlock_irqrestore(&spinlock, flags); |
... | ... | @@ -266,8 +291,8 @@ |
266 | 291 | * wdt_set_timeout - set a new timeout value with watchdog ioctl |
267 | 292 | * @t: timeout value in seconds |
268 | 293 | * |
269 | - * The hardware device has a 16 bit watchdog timer, thus the | |
270 | - * timeout time ranges between 1 and 65535 seconds. | |
294 | + * The hardware device has a 8 or 16 bit watchdog timer (depends on | |
295 | + * chip version) that can be configured to count seconds or minutes. | |
271 | 296 | * |
272 | 297 | * Used within WDIOC_SETTIMEOUT watchdog device ioctl. |
273 | 298 | */ |
274 | 299 | |
275 | 300 | |
276 | 301 | |
... | ... | @@ -276,19 +301,19 @@ |
276 | 301 | { |
277 | 302 | unsigned long flags; |
278 | 303 | |
279 | - if (t < 1 || t > 65535) | |
304 | + if (t < 1 || t > max_units * 60) | |
280 | 305 | return -EINVAL; |
281 | 306 | |
282 | - timeout = t; | |
307 | + if (t > max_units) | |
308 | + timeout = wdt_round_time(t); | |
309 | + else | |
310 | + timeout = t; | |
283 | 311 | |
284 | 312 | spin_lock_irqsave(&spinlock, flags); |
285 | 313 | if (test_bit(WDTS_TIMER_RUN, &wdt_status)) { |
286 | 314 | superio_enter(); |
287 | - | |
288 | 315 | superio_select(GPIO); |
289 | - superio_outb(t>>8, WDTVALMSB); | |
290 | - superio_outb(t, WDTVALLSB); | |
291 | - | |
316 | + wdt_update_timeout(); | |
292 | 317 | superio_exit(); |
293 | 318 | } |
294 | 319 | spin_unlock_irqrestore(&spinlock, flags); |
295 | 320 | |
... | ... | @@ -529,10 +554,13 @@ |
529 | 554 | static int __init it87_wdt_init(void) |
530 | 555 | { |
531 | 556 | int rc = 0; |
557 | + int try_gameport = !nogameport; | |
532 | 558 | u16 chip_type; |
533 | 559 | u8 chip_rev; |
534 | 560 | unsigned long flags; |
535 | 561 | |
562 | + wdt_status = 0; | |
563 | + | |
536 | 564 | spin_lock_irqsave(&spinlock, flags); |
537 | 565 | superio_enter(); |
538 | 566 | chip_type = superio_inw(CHIPID); |
539 | 567 | |
540 | 568 | |
541 | 569 | |
... | ... | @@ -541,13 +569,21 @@ |
541 | 569 | spin_unlock_irqrestore(&spinlock, flags); |
542 | 570 | |
543 | 571 | switch (chip_type) { |
572 | + case IT8702_ID: | |
573 | + max_units = 255; | |
574 | + break; | |
575 | + case IT8712_ID: | |
576 | + max_units = (chip_rev < 8) ? 255 : 65535; | |
577 | + break; | |
544 | 578 | case IT8716_ID: |
545 | - case IT8718_ID: | |
546 | 579 | case IT8726_ID: |
580 | + max_units = 65535; | |
547 | 581 | break; |
548 | - case IT8712_ID: | |
549 | - if (chip_rev > 7) | |
550 | - break; | |
582 | + case IT8718_ID: | |
583 | + case IT8720_ID: | |
584 | + max_units = 65535; | |
585 | + try_gameport = 0; | |
586 | + break; | |
551 | 587 | case IT8705_ID: |
552 | 588 | printk(KERN_ERR PFX |
553 | 589 | "Unsupported Chip found, Chip %04x Revision %02x\n", |
... | ... | @@ -571,7 +607,7 @@ |
571 | 607 | superio_outb(0x00, WDTCTRL); |
572 | 608 | |
573 | 609 | /* First try to get Gameport support */ |
574 | - if (chip_type != IT8718_ID && !nogameport) { | |
610 | + if (try_gameport) { | |
575 | 611 | superio_select(GAMEPORT); |
576 | 612 | base = superio_inw(BASEREG); |
577 | 613 | if (!base) { |
578 | 614 | |
... | ... | @@ -623,13 +659,16 @@ |
623 | 659 | spin_unlock_irqrestore(&spinlock, flags); |
624 | 660 | } |
625 | 661 | |
626 | - if (timeout < 1 || timeout > 65535) { | |
662 | + if (timeout < 1 || timeout > max_units * 60) { | |
627 | 663 | timeout = DEFAULT_TIMEOUT; |
628 | 664 | printk(KERN_WARNING PFX |
629 | 665 | "Timeout value out of range, use default %d sec\n", |
630 | 666 | DEFAULT_TIMEOUT); |
631 | 667 | } |
632 | 668 | |
669 | + if (timeout > max_units) | |
670 | + timeout = wdt_round_time(timeout); | |
671 | + | |
633 | 672 | rc = register_reboot_notifier(&wdt_notifier); |
634 | 673 | if (rc) { |
635 | 674 | printk(KERN_ERR PFX |
... | ... | @@ -656,7 +695,7 @@ |
656 | 695 | outb(0x09, CIR_IER(base)); |
657 | 696 | } |
658 | 697 | |
659 | - printk(KERN_INFO PFX "Chip it%04x revision %d initialized. " | |
698 | + printk(KERN_INFO PFX "Chip IT%04x revision %d initialized. " | |
660 | 699 | "timeout=%d sec (nowayout=%d testmode=%d exclusive=%d " |
661 | 700 | "nogameport=%d)\n", chip_type, chip_rev, timeout, |
662 | 701 | nowayout, testmode, exclusive, nogameport); |
... | ... | @@ -676,7 +715,7 @@ |
676 | 715 | spin_unlock_irqrestore(&spinlock, flags); |
677 | 716 | } |
678 | 717 | err_out: |
679 | - if (chip_type != IT8718_ID && !nogameport) { | |
718 | + if (try_gameport) { | |
680 | 719 | spin_lock_irqsave(&spinlock, flags); |
681 | 720 | superio_enter(); |
682 | 721 | superio_select(GAMEPORT); |
683 | 722 | |
... | ... | @@ -698,8 +737,9 @@ |
698 | 737 | superio_select(GPIO); |
699 | 738 | superio_outb(0x00, WDTCTRL); |
700 | 739 | superio_outb(0x00, WDTCFG); |
701 | - superio_outb(0x00, WDTVALMSB); | |
702 | 740 | superio_outb(0x00, WDTVALLSB); |
741 | + if (max_units > 255) | |
742 | + superio_outb(0x00, WDTVALMSB); | |
703 | 743 | if (test_bit(WDTS_USE_GP, &wdt_status)) { |
704 | 744 | superio_select(GAMEPORT); |
705 | 745 | superio_outb(gpact, ACTREG); |
drivers/watchdog/machzwd.c
... | ... | @@ -143,7 +143,7 @@ |
143 | 143 | #ifndef ZF_DEBUG |
144 | 144 | # define dprintk(format, args...) |
145 | 145 | #else |
146 | -# define dprintk(format, args...) printk(KERN_DEBUG PFX | |
146 | +# define dprintk(format, args...) printk(KERN_DEBUG PFX \ | |
147 | 147 | ":%s:%d: " format, __func__, __LINE__ , ## args) |
148 | 148 | #endif |
149 | 149 | |
... | ... | @@ -388,7 +388,7 @@ |
388 | 388 | |
389 | 389 | static void __init zf_show_action(int act) |
390 | 390 | { |
391 | - char *str[] = { "RESET", "SMI", "NMI", "SCI" }; | |
391 | + static const char * const str[] = { "RESET", "SMI", "NMI", "SCI" }; | |
392 | 392 | |
393 | 393 | printk(KERN_INFO PFX ": Watchdog using action = %s\n", str[act]); |
394 | 394 | } |