diff options
author | Guenter Roeck <linux@roeck-us.net> | 2013-10-28 22:43:57 -0400 |
---|---|---|
committer | Wim Van Sebroeck <wim@iguana.be> | 2013-11-18 15:34:01 -0500 |
commit | 30a83695aa2ed3ffb1445d6daef1e620c3ca4e6d (patch) | |
tree | 26ec7029822b66a043c5230f7711e1998ebb684b | |
parent | 4a7e94a0637da7e1ddce748da49ae780c370eeef (diff) |
watchdog: w83627hf: Convert to watchdog infrastructure
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r-- | drivers/watchdog/Kconfig | 1 | ||||
-rw-r--r-- | drivers/watchdog/w83627hf_wdt.c | 215 |
2 files changed, 48 insertions, 168 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 74f29a2fc51c..5be6e919f785 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig | |||
@@ -885,6 +885,7 @@ config VIA_WDT | |||
885 | config W83627HF_WDT | 885 | config W83627HF_WDT |
886 | tristate "W83627HF/W83627DHG Watchdog Timer" | 886 | tristate "W83627HF/W83627DHG Watchdog Timer" |
887 | depends on X86 | 887 | depends on X86 |
888 | select WATCHDOG_CORE | ||
888 | ---help--- | 889 | ---help--- |
889 | This is the driver for the hardware watchdog on the W83627HF chipset | 890 | This is the driver for the hardware watchdog on the W83627HF chipset |
890 | as used in Advantech PC-9578 and Tyan S2721-533 motherboards | 891 | as used in Advantech PC-9578 and Tyan S2721-533 motherboards |
diff --git a/drivers/watchdog/w83627hf_wdt.c b/drivers/watchdog/w83627hf_wdt.c index da6781c12523..ab5ec6d84b16 100644 --- a/drivers/watchdog/w83627hf_wdt.c +++ b/drivers/watchdog/w83627hf_wdt.c | |||
@@ -1,6 +1,9 @@ | |||
1 | /* | 1 | /* |
2 | * w83627hf/thf WDT driver | 2 | * w83627hf/thf WDT driver |
3 | * | 3 | * |
4 | * (c) Copyright 2013 Guenter Roeck | ||
5 | * converted to watchdog infrastructure | ||
6 | * | ||
4 | * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> | 7 | * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> |
5 | * added support for W83627THF. | 8 | * added support for W83627THF. |
6 | * | 9 | * |
@@ -31,31 +34,22 @@ | |||
31 | #include <linux/module.h> | 34 | #include <linux/module.h> |
32 | #include <linux/moduleparam.h> | 35 | #include <linux/moduleparam.h> |
33 | #include <linux/types.h> | 36 | #include <linux/types.h> |
34 | #include <linux/miscdevice.h> | ||
35 | #include <linux/watchdog.h> | 37 | #include <linux/watchdog.h> |
36 | #include <linux/fs.h> | ||
37 | #include <linux/ioport.h> | 38 | #include <linux/ioport.h> |
38 | #include <linux/notifier.h> | 39 | #include <linux/notifier.h> |
39 | #include <linux/reboot.h> | 40 | #include <linux/reboot.h> |
40 | #include <linux/init.h> | 41 | #include <linux/init.h> |
41 | #include <linux/spinlock.h> | ||
42 | #include <linux/io.h> | 42 | #include <linux/io.h> |
43 | #include <linux/uaccess.h> | ||
44 | |||
45 | 43 | ||
46 | #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" | 44 | #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" |
47 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ | 45 | #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ |
48 | 46 | ||
49 | static unsigned long wdt_is_open; | ||
50 | static char expect_close; | ||
51 | static DEFINE_SPINLOCK(io_lock); | ||
52 | |||
53 | /* You must set this - there is no sane way to probe for this board. */ | 47 | /* You must set this - there is no sane way to probe for this board. */ |
54 | static int wdt_io = 0x2E; | 48 | static int wdt_io = 0x2E; |
55 | module_param(wdt_io, int, 0); | 49 | module_param(wdt_io, int, 0); |
56 | MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); | 50 | MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); |
57 | 51 | ||
58 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ | 52 | static int timeout; /* in seconds */ |
59 | module_param(timeout, int, 0); | 53 | module_param(timeout, int, 0); |
60 | MODULE_PARM_DESC(timeout, | 54 | MODULE_PARM_DESC(timeout, |
61 | "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" | 55 | "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" |
@@ -110,7 +104,7 @@ static void w83627hf_unselect_wd_register(void) | |||
110 | /* tyan motherboards seem to set F5 to 0x4C ? | 104 | /* tyan motherboards seem to set F5 to 0x4C ? |
111 | * So explicitly init to appropriate value. */ | 105 | * So explicitly init to appropriate value. */ |
112 | 106 | ||
113 | static void w83627hf_init(void) | 107 | static void w83627hf_init(struct watchdog_device *wdog) |
114 | { | 108 | { |
115 | unsigned char t; | 109 | unsigned char t; |
116 | 110 | ||
@@ -120,8 +114,8 @@ static void w83627hf_init(void) | |||
120 | t = inb_p(WDT_EFDR); /* read CRF6 */ | 114 | t = inb_p(WDT_EFDR); /* read CRF6 */ |
121 | if (t != 0) { | 115 | if (t != 0) { |
122 | pr_info("Watchdog already running. Resetting timeout to %d sec\n", | 116 | pr_info("Watchdog already running. Resetting timeout to %d sec\n", |
123 | timeout); | 117 | wdog->timeout); |
124 | outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ | 118 | outb_p(wdog->timeout, WDT_EFDR); /* Write back to CRF6 */ |
125 | } | 119 | } |
126 | 120 | ||
127 | outb_p(0xF5, WDT_EFER); /* Select CRF5 */ | 121 | outb_p(0xF5, WDT_EFER); /* Select CRF5 */ |
@@ -141,10 +135,8 @@ static void w83627hf_init(void) | |||
141 | w83627hf_unselect_wd_register(); | 135 | w83627hf_unselect_wd_register(); |
142 | } | 136 | } |
143 | 137 | ||
144 | static void wdt_set_time(int timeout) | 138 | static int wdt_set_time(unsigned int timeout) |
145 | { | 139 | { |
146 | spin_lock(&io_lock); | ||
147 | |||
148 | w83627hf_select_wd_register(); | 140 | w83627hf_select_wd_register(); |
149 | 141 | ||
150 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ | 142 | outb_p(0xF6, WDT_EFER); /* Select CRF6 */ |
@@ -152,34 +144,29 @@ static void wdt_set_time(int timeout) | |||
152 | 144 | ||
153 | w83627hf_unselect_wd_register(); | 145 | w83627hf_unselect_wd_register(); |
154 | 146 | ||
155 | spin_unlock(&io_lock); | 147 | return 0; |
156 | } | 148 | } |
157 | 149 | ||
158 | static int wdt_ping(void) | 150 | static int wdt_start(struct watchdog_device *wdog) |
159 | { | 151 | { |
160 | wdt_set_time(timeout); | 152 | return wdt_set_time(wdog->timeout); |
161 | return 0; | ||
162 | } | 153 | } |
163 | 154 | ||
164 | static int wdt_disable(void) | 155 | static int wdt_stop(struct watchdog_device *wdog) |
165 | { | 156 | { |
166 | wdt_set_time(0); | 157 | return wdt_set_time(0); |
167 | return 0; | ||
168 | } | 158 | } |
169 | 159 | ||
170 | static int wdt_set_heartbeat(int t) | 160 | static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout) |
171 | { | 161 | { |
172 | if (t < 1 || t > 255) | 162 | wdog->timeout = timeout; |
173 | return -EINVAL; | 163 | |
174 | timeout = t; | ||
175 | return 0; | 164 | return 0; |
176 | } | 165 | } |
177 | 166 | ||
178 | static int wdt_get_time(void) | 167 | static unsigned int wdt_get_time(struct watchdog_device *wdog) |
179 | { | 168 | { |
180 | int timeleft; | 169 | unsigned int timeleft; |
181 | |||
182 | spin_lock(&io_lock); | ||
183 | 170 | ||
184 | w83627hf_select_wd_register(); | 171 | w83627hf_select_wd_register(); |
185 | 172 | ||
@@ -188,124 +175,17 @@ static int wdt_get_time(void) | |||
188 | 175 | ||
189 | w83627hf_unselect_wd_register(); | 176 | w83627hf_unselect_wd_register(); |
190 | 177 | ||
191 | spin_unlock(&io_lock); | ||
192 | |||
193 | return timeleft; | 178 | return timeleft; |
194 | } | 179 | } |
195 | 180 | ||
196 | static ssize_t wdt_write(struct file *file, const char __user *buf, | ||
197 | size_t count, loff_t *ppos) | ||
198 | { | ||
199 | if (count) { | ||
200 | if (!nowayout) { | ||
201 | size_t i; | ||
202 | |||
203 | expect_close = 0; | ||
204 | |||
205 | for (i = 0; i != count; i++) { | ||
206 | char c; | ||
207 | if (get_user(c, buf + i)) | ||
208 | return -EFAULT; | ||
209 | if (c == 'V') | ||
210 | expect_close = 42; | ||
211 | } | ||
212 | } | ||
213 | wdt_ping(); | ||
214 | } | ||
215 | return count; | ||
216 | } | ||
217 | |||
218 | static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | ||
219 | { | ||
220 | void __user *argp = (void __user *)arg; | ||
221 | int __user *p = argp; | ||
222 | int timeval; | ||
223 | static const struct watchdog_info ident = { | ||
224 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | | ||
225 | WDIOF_MAGICCLOSE, | ||
226 | .firmware_version = 1, | ||
227 | .identity = "W83627HF WDT", | ||
228 | }; | ||
229 | |||
230 | switch (cmd) { | ||
231 | case WDIOC_GETSUPPORT: | ||
232 | if (copy_to_user(argp, &ident, sizeof(ident))) | ||
233 | return -EFAULT; | ||
234 | break; | ||
235 | case WDIOC_GETSTATUS: | ||
236 | case WDIOC_GETBOOTSTATUS: | ||
237 | return put_user(0, p); | ||
238 | case WDIOC_SETOPTIONS: | ||
239 | { | ||
240 | int options, retval = -EINVAL; | ||
241 | |||
242 | if (get_user(options, p)) | ||
243 | return -EFAULT; | ||
244 | if (options & WDIOS_DISABLECARD) { | ||
245 | wdt_disable(); | ||
246 | retval = 0; | ||
247 | } | ||
248 | if (options & WDIOS_ENABLECARD) { | ||
249 | wdt_ping(); | ||
250 | retval = 0; | ||
251 | } | ||
252 | return retval; | ||
253 | } | ||
254 | case WDIOC_KEEPALIVE: | ||
255 | wdt_ping(); | ||
256 | break; | ||
257 | case WDIOC_SETTIMEOUT: | ||
258 | if (get_user(timeval, p)) | ||
259 | return -EFAULT; | ||
260 | if (wdt_set_heartbeat(timeval)) | ||
261 | return -EINVAL; | ||
262 | wdt_ping(); | ||
263 | /* Fall */ | ||
264 | case WDIOC_GETTIMEOUT: | ||
265 | return put_user(timeout, p); | ||
266 | case WDIOC_GETTIMELEFT: | ||
267 | timeval = wdt_get_time(); | ||
268 | return put_user(timeval, p); | ||
269 | default: | ||
270 | return -ENOTTY; | ||
271 | } | ||
272 | return 0; | ||
273 | } | ||
274 | |||
275 | static int wdt_open(struct inode *inode, struct file *file) | ||
276 | { | ||
277 | if (test_and_set_bit(0, &wdt_is_open)) | ||
278 | return -EBUSY; | ||
279 | /* | ||
280 | * Activate | ||
281 | */ | ||
282 | |||
283 | wdt_ping(); | ||
284 | return nonseekable_open(inode, file); | ||
285 | } | ||
286 | |||
287 | static int wdt_close(struct inode *inode, struct file *file) | ||
288 | { | ||
289 | if (expect_close == 42) | ||
290 | wdt_disable(); | ||
291 | else { | ||
292 | pr_crit("Unexpected close, not stopping watchdog!\n"); | ||
293 | wdt_ping(); | ||
294 | } | ||
295 | expect_close = 0; | ||
296 | clear_bit(0, &wdt_is_open); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /* | 181 | /* |
301 | * Notifier for system down | 182 | * Notifier for system down |
302 | */ | 183 | */ |
303 | |||
304 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 184 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
305 | void *unused) | 185 | void *unused) |
306 | { | 186 | { |
307 | if (code == SYS_DOWN || code == SYS_HALT) | 187 | if (code == SYS_DOWN || code == SYS_HALT) |
308 | wdt_disable(); /* Turn the WDT off */ | 188 | wdt_set_time(0); /* Turn the WDT off */ |
309 | 189 | ||
310 | return NOTIFY_DONE; | 190 | return NOTIFY_DONE; |
311 | } | 191 | } |
@@ -314,19 +194,25 @@ static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | |||
314 | * Kernel Interfaces | 194 | * Kernel Interfaces |
315 | */ | 195 | */ |
316 | 196 | ||
317 | static const struct file_operations wdt_fops = { | 197 | static struct watchdog_info wdt_info = { |
318 | .owner = THIS_MODULE, | 198 | .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, |
319 | .llseek = no_llseek, | 199 | .identity = "W83627HF Watchdog", |
320 | .write = wdt_write, | ||
321 | .unlocked_ioctl = wdt_ioctl, | ||
322 | .open = wdt_open, | ||
323 | .release = wdt_close, | ||
324 | }; | 200 | }; |
325 | 201 | ||
326 | static struct miscdevice wdt_miscdev = { | 202 | static struct watchdog_ops wdt_ops = { |
327 | .minor = WATCHDOG_MINOR, | 203 | .owner = THIS_MODULE, |
328 | .name = "watchdog", | 204 | .start = wdt_start, |
329 | .fops = &wdt_fops, | 205 | .stop = wdt_stop, |
206 | .set_timeout = wdt_set_timeout, | ||
207 | .get_timeleft = wdt_get_time, | ||
208 | }; | ||
209 | |||
210 | static struct watchdog_device wdt_dev = { | ||
211 | .info = &wdt_info, | ||
212 | .ops = &wdt_ops, | ||
213 | .timeout = WATCHDOG_TIMEOUT, | ||
214 | .min_timeout = 1, | ||
215 | .max_timeout = 255, | ||
330 | }; | 216 | }; |
331 | 217 | ||
332 | /* | 218 | /* |
@@ -344,19 +230,15 @@ static int __init wdt_init(void) | |||
344 | 230 | ||
345 | pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); | 231 | pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); |
346 | 232 | ||
347 | if (wdt_set_heartbeat(timeout)) { | ||
348 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | ||
349 | pr_info("timeout value must be 1 <= timeout <= 255, using %d\n", | ||
350 | WATCHDOG_TIMEOUT); | ||
351 | } | ||
352 | |||
353 | if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { | 233 | if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { |
354 | pr_err("I/O address 0x%04x already in use\n", wdt_io); | 234 | pr_err("I/O address 0x%04x already in use\n", wdt_io); |
355 | ret = -EIO; | 235 | return -EIO; |
356 | goto out; | ||
357 | } | 236 | } |
358 | 237 | ||
359 | w83627hf_init(); | 238 | watchdog_init_timeout(&wdt_dev, timeout, NULL); |
239 | watchdog_set_nowayout(&wdt_dev, nowayout); | ||
240 | |||
241 | w83627hf_init(&wdt_dev); | ||
360 | 242 | ||
361 | ret = register_reboot_notifier(&wdt_notifier); | 243 | ret = register_reboot_notifier(&wdt_notifier); |
362 | if (ret != 0) { | 244 | if (ret != 0) { |
@@ -364,28 +246,25 @@ static int __init wdt_init(void) | |||
364 | goto unreg_regions; | 246 | goto unreg_regions; |
365 | } | 247 | } |
366 | 248 | ||
367 | ret = misc_register(&wdt_miscdev); | 249 | ret = watchdog_register_device(&wdt_dev); |
368 | if (ret != 0) { | 250 | if (ret) |
369 | pr_err("cannot register miscdev on minor=%d (err=%d)\n", | ||
370 | WATCHDOG_MINOR, ret); | ||
371 | goto unreg_reboot; | 251 | goto unreg_reboot; |
372 | } | ||
373 | 252 | ||
374 | pr_info("initialized. timeout=%d sec (nowayout=%d)\n", | 253 | pr_info("initialized. timeout=%d sec (nowayout=%d)\n", |
375 | timeout, nowayout); | 254 | wdt_dev.timeout, nowayout); |
376 | 255 | ||
377 | out: | ||
378 | return ret; | 256 | return ret; |
257 | |||
379 | unreg_reboot: | 258 | unreg_reboot: |
380 | unregister_reboot_notifier(&wdt_notifier); | 259 | unregister_reboot_notifier(&wdt_notifier); |
381 | unreg_regions: | 260 | unreg_regions: |
382 | release_region(wdt_io, 1); | 261 | release_region(wdt_io, 1); |
383 | goto out; | 262 | return ret; |
384 | } | 263 | } |
385 | 264 | ||
386 | static void __exit wdt_exit(void) | 265 | static void __exit wdt_exit(void) |
387 | { | 266 | { |
388 | misc_deregister(&wdt_miscdev); | 267 | watchdog_unregister_device(&wdt_dev); |
389 | unregister_reboot_notifier(&wdt_notifier); | 268 | unregister_reboot_notifier(&wdt_notifier); |
390 | release_region(wdt_io, 1); | 269 | release_region(wdt_io, 1); |
391 | } | 270 | } |