diff options
Diffstat (limited to 'drivers/watchdog/sc520_wdt.c')
-rw-r--r-- | drivers/watchdog/sc520_wdt.c | 161 |
1 files changed, 86 insertions, 75 deletions
diff --git a/drivers/watchdog/sc520_wdt.c b/drivers/watchdog/sc520_wdt.c index 2847324a2be2..525555a8779c 100644 --- a/drivers/watchdog/sc520_wdt.c +++ b/drivers/watchdog/sc520_wdt.c | |||
@@ -64,9 +64,9 @@ | |||
64 | #include <linux/reboot.h> | 64 | #include <linux/reboot.h> |
65 | #include <linux/init.h> | 65 | #include <linux/init.h> |
66 | #include <linux/jiffies.h> | 66 | #include <linux/jiffies.h> |
67 | #include <linux/io.h> | ||
68 | #include <linux/uaccess.h> | ||
67 | 69 | ||
68 | #include <asm/io.h> | ||
69 | #include <asm/uaccess.h> | ||
70 | #include <asm/system.h> | 70 | #include <asm/system.h> |
71 | 71 | ||
72 | #define OUR_NAME "sc520_wdt" | 72 | #define OUR_NAME "sc520_wdt" |
@@ -91,13 +91,18 @@ | |||
91 | */ | 91 | */ |
92 | 92 | ||
93 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ | 93 | #define WATCHDOG_TIMEOUT 30 /* 30 sec default timeout */ |
94 | static int timeout = WATCHDOG_TIMEOUT; /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ | 94 | /* in seconds, will be multiplied by HZ to get seconds to wait for a ping */ |
95 | static int timeout = WATCHDOG_TIMEOUT; | ||
95 | module_param(timeout, int, 0); | 96 | module_param(timeout, int, 0); |
96 | MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds. (1<=timeout<=3600, default=" __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | 97 | MODULE_PARM_DESC(timeout, |
98 | "Watchdog timeout in seconds. (1 <= timeout <= 3600, default=" | ||
99 | __MODULE_STRING(WATCHDOG_TIMEOUT) ")"); | ||
97 | 100 | ||
98 | static int nowayout = WATCHDOG_NOWAYOUT; | 101 | static int nowayout = WATCHDOG_NOWAYOUT; |
99 | module_param(nowayout, int, 0); | 102 | module_param(nowayout, int, 0); |
100 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 103 | MODULE_PARM_DESC(nowayout, |
104 | "Watchdog cannot be stopped once started (default=" | ||
105 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | ||
101 | 106 | ||
102 | /* | 107 | /* |
103 | * AMD Elan SC520 - Watchdog Timer Registers | 108 | * AMD Elan SC520 - Watchdog Timer Registers |
@@ -136,8 +141,7 @@ static void wdt_timer_ping(unsigned long data) | |||
136 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL | 141 | /* If we got a heartbeat pulse within the WDT_US_INTERVAL |
137 | * we agree to ping the WDT | 142 | * we agree to ping the WDT |
138 | */ | 143 | */ |
139 | if(time_before(jiffies, next_heartbeat)) | 144 | if (time_before(jiffies, next_heartbeat)) { |
140 | { | ||
141 | /* Ping the WDT */ | 145 | /* Ping the WDT */ |
142 | spin_lock(&wdt_spinlock); | 146 | spin_lock(&wdt_spinlock); |
143 | writew(0xAAAA, wdtmrctl); | 147 | writew(0xAAAA, wdtmrctl); |
@@ -146,9 +150,9 @@ static void wdt_timer_ping(unsigned long data) | |||
146 | 150 | ||
147 | /* Re-set the timer interval */ | 151 | /* Re-set the timer interval */ |
148 | mod_timer(&timer, jiffies + WDT_INTERVAL); | 152 | mod_timer(&timer, jiffies + WDT_INTERVAL); |
149 | } else { | 153 | } else |
150 | printk(KERN_WARNING PFX "Heartbeat lost! Will not ping the watchdog\n"); | 154 | printk(KERN_WARNING PFX |
151 | } | 155 | "Heartbeat lost! Will not ping the watchdog\n"); |
152 | } | 156 | } |
153 | 157 | ||
154 | /* | 158 | /* |
@@ -162,7 +166,7 @@ static void wdt_config(int writeval) | |||
162 | 166 | ||
163 | /* buy some time (ping) */ | 167 | /* buy some time (ping) */ |
164 | spin_lock_irqsave(&wdt_spinlock, flags); | 168 | spin_lock_irqsave(&wdt_spinlock, flags); |
165 | dummy=readw(wdtmrctl); /* ensure write synchronization */ | 169 | dummy = readw(wdtmrctl); /* ensure write synchronization */ |
166 | writew(0xAAAA, wdtmrctl); | 170 | writew(0xAAAA, wdtmrctl); |
167 | writew(0x5555, wdtmrctl); | 171 | writew(0x5555, wdtmrctl); |
168 | /* unlock WDT = make WDT configuration register writable one time */ | 172 | /* unlock WDT = make WDT configuration register writable one time */ |
@@ -219,10 +223,11 @@ static int wdt_set_heartbeat(int t) | |||
219 | * /dev/watchdog handling | 223 | * /dev/watchdog handling |
220 | */ | 224 | */ |
221 | 225 | ||
222 | static ssize_t fop_write(struct file * file, const char __user * buf, size_t count, loff_t * ppos) | 226 | static ssize_t fop_write(struct file *file, const char __user *buf, |
227 | size_t count, loff_t *ppos) | ||
223 | { | 228 | { |
224 | /* See if we got the magic character 'V' and reload the timer */ | 229 | /* See if we got the magic character 'V' and reload the timer */ |
225 | if(count) { | 230 | if (count) { |
226 | if (!nowayout) { | 231 | if (!nowayout) { |
227 | size_t ofs; | 232 | size_t ofs; |
228 | 233 | ||
@@ -231,25 +236,26 @@ static ssize_t fop_write(struct file * file, const char __user * buf, size_t cou | |||
231 | wdt_expect_close = 0; | 236 | wdt_expect_close = 0; |
232 | 237 | ||
233 | /* now scan */ | 238 | /* now scan */ |
234 | for(ofs = 0; ofs != count; ofs++) { | 239 | for (ofs = 0; ofs != count; ofs++) { |
235 | char c; | 240 | char c; |
236 | if (get_user(c, buf + ofs)) | 241 | if (get_user(c, buf + ofs)) |
237 | return -EFAULT; | 242 | return -EFAULT; |
238 | if(c == 'V') | 243 | if (c == 'V') |
239 | wdt_expect_close = 42; | 244 | wdt_expect_close = 42; |
240 | } | 245 | } |
241 | } | 246 | } |
242 | 247 | ||
243 | /* Well, anyhow someone wrote to us, we should return that favour */ | 248 | /* Well, anyhow someone wrote to us, we should |
249 | return that favour */ | ||
244 | wdt_keepalive(); | 250 | wdt_keepalive(); |
245 | } | 251 | } |
246 | return count; | 252 | return count; |
247 | } | 253 | } |
248 | 254 | ||
249 | static int fop_open(struct inode * inode, struct file * file) | 255 | static int fop_open(struct inode *inode, struct file *file) |
250 | { | 256 | { |
251 | /* Just in case we're already talking to someone... */ | 257 | /* Just in case we're already talking to someone... */ |
252 | if(test_and_set_bit(0, &wdt_is_open)) | 258 | if (test_and_set_bit(0, &wdt_is_open)) |
253 | return -EBUSY; | 259 | return -EBUSY; |
254 | if (nowayout) | 260 | if (nowayout) |
255 | __module_get(THIS_MODULE); | 261 | __module_get(THIS_MODULE); |
@@ -259,12 +265,13 @@ static int fop_open(struct inode * inode, struct file * file) | |||
259 | return nonseekable_open(inode, file); | 265 | return nonseekable_open(inode, file); |
260 | } | 266 | } |
261 | 267 | ||
262 | static int fop_close(struct inode * inode, struct file * file) | 268 | static int fop_close(struct inode *inode, struct file *file) |
263 | { | 269 | { |
264 | if(wdt_expect_close == 42) { | 270 | if (wdt_expect_close == 42) |
265 | wdt_turnoff(); | 271 | wdt_turnoff(); |
266 | } else { | 272 | else { |
267 | printk(KERN_CRIT PFX "Unexpected close, not stopping watchdog!\n"); | 273 | printk(KERN_CRIT PFX |
274 | "Unexpected close, not stopping watchdog!\n"); | ||
268 | wdt_keepalive(); | 275 | wdt_keepalive(); |
269 | } | 276 | } |
270 | clear_bit(0, &wdt_is_open); | 277 | clear_bit(0, &wdt_is_open); |
@@ -272,63 +279,63 @@ static int fop_close(struct inode * inode, struct file * file) | |||
272 | return 0; | 279 | return 0; |
273 | } | 280 | } |
274 | 281 | ||
275 | static int fop_ioctl(struct inode *inode, struct file *file, unsigned int cmd, | 282 | static int fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
276 | unsigned long arg) | ||
277 | { | 283 | { |
278 | void __user *argp = (void __user *)arg; | 284 | void __user *argp = (void __user *)arg; |
279 | int __user *p = argp; | 285 | int __user *p = argp; |
280 | static struct watchdog_info ident = { | 286 | static const struct watchdog_info ident = { |
281 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, | 287 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT |
288 | | WDIOF_MAGICCLOSE, | ||
282 | .firmware_version = 1, | 289 | .firmware_version = 1, |
283 | .identity = "SC520", | 290 | .identity = "SC520", |
284 | }; | 291 | }; |
285 | 292 | ||
286 | switch(cmd) | 293 | switch (cmd) |
287 | { | 294 | { |
288 | default: | 295 | default: |
289 | return -ENOTTY; | 296 | return -ENOTTY; |
290 | case WDIOC_GETSUPPORT: | 297 | case WDIOC_GETSUPPORT: |
291 | return copy_to_user(argp, &ident, sizeof(ident))?-EFAULT:0; | 298 | return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0; |
292 | case WDIOC_GETSTATUS: | 299 | case WDIOC_GETSTATUS: |
293 | case WDIOC_GETBOOTSTATUS: | 300 | case WDIOC_GETBOOTSTATUS: |
294 | return put_user(0, p); | 301 | return put_user(0, p); |
295 | case WDIOC_KEEPALIVE: | 302 | case WDIOC_KEEPALIVE: |
296 | wdt_keepalive(); | 303 | wdt_keepalive(); |
297 | return 0; | 304 | return 0; |
298 | case WDIOC_SETOPTIONS: | 305 | case WDIOC_SETOPTIONS: |
299 | { | 306 | { |
300 | int new_options, retval = -EINVAL; | 307 | int new_options, retval = -EINVAL; |
301 | |||
302 | if(get_user(new_options, p)) | ||
303 | return -EFAULT; | ||
304 | |||
305 | if(new_options & WDIOS_DISABLECARD) { | ||
306 | wdt_turnoff(); | ||
307 | retval = 0; | ||
308 | } | ||
309 | 308 | ||
310 | if(new_options & WDIOS_ENABLECARD) { | 309 | if (get_user(new_options, p)) |
311 | wdt_startup(); | 310 | return -EFAULT; |
312 | retval = 0; | 311 | |
313 | } | 312 | if (new_options & WDIOS_DISABLECARD) { |
313 | wdt_turnoff(); | ||
314 | retval = 0; | ||
315 | } | ||
314 | 316 | ||
315 | return retval; | 317 | if (new_options & WDIOS_ENABLECARD) { |
318 | wdt_startup(); | ||
319 | retval = 0; | ||
316 | } | 320 | } |
317 | case WDIOC_SETTIMEOUT: | ||
318 | { | ||
319 | int new_timeout; | ||
320 | 321 | ||
321 | if(get_user(new_timeout, p)) | 322 | return retval; |
322 | return -EFAULT; | 323 | } |
324 | case WDIOC_SETTIMEOUT: | ||
325 | { | ||
326 | int new_timeout; | ||
323 | 327 | ||
324 | if(wdt_set_heartbeat(new_timeout)) | 328 | if (get_user(new_timeout, p)) |
325 | return -EINVAL; | 329 | return -EFAULT; |
326 | 330 | ||
327 | wdt_keepalive(); | 331 | if (wdt_set_heartbeat(new_timeout)) |
328 | /* Fall through */ | 332 | return -EINVAL; |
329 | } | 333 | |
330 | case WDIOC_GETTIMEOUT: | 334 | wdt_keepalive(); |
331 | return put_user(timeout, p); | 335 | /* Fall through */ |
336 | } | ||
337 | case WDIOC_GETTIMEOUT: | ||
338 | return put_user(timeout, p); | ||
332 | } | 339 | } |
333 | } | 340 | } |
334 | 341 | ||
@@ -354,7 +361,7 @@ static struct miscdevice wdt_miscdev = { | |||
354 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, | 361 | static int wdt_notify_sys(struct notifier_block *this, unsigned long code, |
355 | void *unused) | 362 | void *unused) |
356 | { | 363 | { |
357 | if(code==SYS_DOWN || code==SYS_HALT) | 364 | if (code == SYS_DOWN || code == SYS_HALT) |
358 | wdt_turnoff(); | 365 | wdt_turnoff(); |
359 | return NOTIFY_DONE; | 366 | return NOTIFY_DONE; |
360 | } | 367 | } |
@@ -383,11 +390,13 @@ static int __init sc520_wdt_init(void) | |||
383 | { | 390 | { |
384 | int rc = -EBUSY; | 391 | int rc = -EBUSY; |
385 | 392 | ||
386 | /* Check that the timeout value is within it's range ; if not reset to the default */ | 393 | /* Check that the timeout value is within it's range ; |
394 | if not reset to the default */ | ||
387 | if (wdt_set_heartbeat(timeout)) { | 395 | if (wdt_set_heartbeat(timeout)) { |
388 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); | 396 | wdt_set_heartbeat(WATCHDOG_TIMEOUT); |
389 | printk(KERN_INFO PFX "timeout value must be 1<=timeout<=3600, using %d\n", | 397 | printk(KERN_INFO PFX |
390 | WATCHDOG_TIMEOUT); | 398 | "timeout value must be 1 <= timeout <= 3600, using %d\n", |
399 | WATCHDOG_TIMEOUT); | ||
391 | } | 400 | } |
392 | 401 | ||
393 | wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); | 402 | wdtmrctl = ioremap((unsigned long)(MMCR_BASE + OFFS_WDTMRCTL), 2); |
@@ -399,20 +408,22 @@ static int __init sc520_wdt_init(void) | |||
399 | 408 | ||
400 | rc = register_reboot_notifier(&wdt_notifier); | 409 | rc = register_reboot_notifier(&wdt_notifier); |
401 | if (rc) { | 410 | if (rc) { |
402 | printk(KERN_ERR PFX "cannot register reboot notifier (err=%d)\n", | 411 | printk(KERN_ERR PFX |
403 | rc); | 412 | "cannot register reboot notifier (err=%d)\n", rc); |
404 | goto err_out_ioremap; | 413 | goto err_out_ioremap; |
405 | } | 414 | } |
406 | 415 | ||
407 | rc = misc_register(&wdt_miscdev); | 416 | rc = misc_register(&wdt_miscdev); |
408 | if (rc) { | 417 | if (rc) { |
409 | printk(KERN_ERR PFX "cannot register miscdev on minor=%d (err=%d)\n", | 418 | printk(KERN_ERR PFX |
410 | WATCHDOG_MINOR, rc); | 419 | "cannot register miscdev on minor=%d (err=%d)\n", |
420 | WATCHDOG_MINOR, rc); | ||
411 | goto err_out_notifier; | 421 | goto err_out_notifier; |
412 | } | 422 | } |
413 | 423 | ||
414 | printk(KERN_INFO PFX "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", | 424 | printk(KERN_INFO PFX |
415 | timeout,nowayout); | 425 | "WDT driver for SC520 initialised. timeout=%d sec (nowayout=%d)\n", |
426 | timeout, nowayout); | ||
416 | 427 | ||
417 | return 0; | 428 | return 0; |
418 | 429 | ||