aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/watchdog/cpwd.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/watchdog/cpwd.c')
-rw-r--r--drivers/watchdog/cpwd.c101
1 files changed, 51 insertions, 50 deletions
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c
index 084dfe9cecfb..41070e4771a0 100644
--- a/drivers/watchdog/cpwd.c
+++ b/drivers/watchdog/cpwd.c
@@ -1,13 +1,13 @@
1/* cpwd.c - driver implementation for hardware watchdog 1/* cpwd.c - driver implementation for hardware watchdog
2 * timers found on Sun Microsystems CP1400 and CP1500 boards. 2 * timers found on Sun Microsystems CP1400 and CP1500 boards.
3 * 3 *
4 * This device supports both the generic Linux watchdog 4 * This device supports both the generic Linux watchdog
5 * interface and Solaris-compatible ioctls as best it is 5 * interface and Solaris-compatible ioctls as best it is
6 * able. 6 * able.
7 * 7 *
8 * NOTE: CP1400 systems appear to have a defective intr_mask 8 * NOTE: CP1400 systems appear to have a defective intr_mask
9 * register on the PLD, preventing the disabling of 9 * register on the PLD, preventing the disabling of
10 * timer interrupts. We use a timer to periodically 10 * timer interrupts. We use a timer to periodically
11 * reset 'stopped' watchdogs on affected platforms. 11 * reset 'stopped' watchdogs on affected platforms.
12 * 12 *
13 * Copyright (c) 2000 Eric Brower (ebrower@usa.net) 13 * Copyright (c) 2000 Eric Brower (ebrower@usa.net)
@@ -28,10 +28,9 @@
28#include <linux/io.h> 28#include <linux/io.h>
29#include <linux/of.h> 29#include <linux/of.h>
30#include <linux/of_device.h> 30#include <linux/of_device.h>
31#include <linux/uaccess.h>
31 32
32#include <asm/irq.h> 33#include <asm/irq.h>
33#include <asm/uaccess.h>
34
35#include <asm/watchdog.h> 34#include <asm/watchdog.h>
36 35
37#define DRIVER_NAME "cpwd" 36#define DRIVER_NAME "cpwd"
@@ -43,8 +42,8 @@
43#define WD_BLIMIT 0xFFFF 42#define WD_BLIMIT 0xFFFF
44 43
45#define WD0_MINOR 212 44#define WD0_MINOR 212
46#define WD1_MINOR 213 45#define WD1_MINOR 213
47#define WD2_MINOR 214 46#define WD2_MINOR 214
48 47
49/* Internal driver definitions. */ 48/* Internal driver definitions. */
50#define WD0_ID 0 49#define WD0_ID 0
@@ -91,16 +90,16 @@ struct cpwd {
91 90
92static struct cpwd *cpwd_device; 91static struct cpwd *cpwd_device;
93 92
94/* Sun uses Altera PLD EPF8820ATC144-4 93/* Sun uses Altera PLD EPF8820ATC144-4
95 * providing three hardware watchdogs: 94 * providing three hardware watchdogs:
96 * 95 *
97 * 1) RIC - sends an interrupt when triggered 96 * 1) RIC - sends an interrupt when triggered
98 * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU 97 * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU
99 * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board 98 * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board
100 * 99 *
101 *** Timer register block definition (struct wd_timer_regblk) 100 *** Timer register block definition (struct wd_timer_regblk)
102 * 101 *
103 * dcntr and limit registers (halfword access): 102 * dcntr and limit registers (halfword access):
104 * ------------------- 103 * -------------------
105 * | 15 | ...| 1 | 0 | 104 * | 15 | ...| 1 | 0 |
106 * ------------------- 105 * -------------------
@@ -108,7 +107,8 @@ static struct cpwd *cpwd_device;
108 * ------------------- 107 * -------------------
109 * dcntr - Current 16-bit downcounter value. 108 * dcntr - Current 16-bit downcounter value.
110 * When downcounter reaches '0' watchdog expires. 109 * When downcounter reaches '0' watchdog expires.
111 * Reading this register resets downcounter with 'limit' value. 110 * Reading this register resets downcounter with
111 * 'limit' value.
112 * limit - 16-bit countdown value in 1/10th second increments. 112 * limit - 16-bit countdown value in 1/10th second increments.
113 * Writing this register begins countdown with input value. 113 * Writing this register begins countdown with input value.
114 * Reading from this register does not affect counter. 114 * Reading from this register does not affect counter.
@@ -158,11 +158,11 @@ static int wd0_timeout = 0;
158static int wd1_timeout = 0; 158static int wd1_timeout = 0;
159static int wd2_timeout = 0; 159static int wd2_timeout = 0;
160 160
161module_param (wd0_timeout, int, 0); 161module_param(wd0_timeout, int, 0);
162MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); 162MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
163module_param (wd1_timeout, int, 0); 163module_param(wd1_timeout, int, 0);
164MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); 164MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
165module_param (wd2_timeout, int, 0); 165module_param(wd2_timeout, int, 0);
166MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); 166MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
167 167
168MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); 168MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
@@ -201,9 +201,9 @@ static u8 cpwd_readb(void __iomem *addr)
201static void cpwd_toggleintr(struct cpwd *p, int index, int enable) 201static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
202{ 202{
203 unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); 203 unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
204 unsigned char setregs = 204 unsigned char setregs =
205 (index == -1) ? 205 (index == -1) ?
206 (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : 206 (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) :
207 (p->devs[index].intr_mask); 207 (p->devs[index].intr_mask);
208 208
209 if (enable == WD_INTR_ON) 209 if (enable == WD_INTR_ON)
@@ -303,24 +303,24 @@ static int cpwd_getstatus(struct cpwd *p, int index)
303 unsigned char ret = WD_STOPPED; 303 unsigned char ret = WD_STOPPED;
304 304
305 /* determine STOPPED */ 305 /* determine STOPPED */
306 if (!stat) 306 if (!stat)
307 return ret; 307 return ret;
308 308
309 /* determine EXPIRED vs FREERUN vs RUNNING */ 309 /* determine EXPIRED vs FREERUN vs RUNNING */
310 else if (WD_S_EXPIRED & stat) { 310 else if (WD_S_EXPIRED & stat) {
311 ret = WD_EXPIRED; 311 ret = WD_EXPIRED;
312 } else if(WD_S_RUNNING & stat) { 312 } else if (WD_S_RUNNING & stat) {
313 if (intr & p->devs[index].intr_mask) { 313 if (intr & p->devs[index].intr_mask) {
314 ret = WD_FREERUN; 314 ret = WD_FREERUN;
315 } else { 315 } else {
316 /* Fudge WD_EXPIRED status for defective CP1400-- 316 /* Fudge WD_EXPIRED status for defective CP1400--
317 * IF timer is running 317 * IF timer is running
318 * AND brokenstop is set 318 * AND brokenstop is set
319 * AND an interrupt has been serviced 319 * AND an interrupt has been serviced
320 * we are WD_EXPIRED. 320 * we are WD_EXPIRED.
321 * 321 *
322 * IF timer is running 322 * IF timer is running
323 * AND brokenstop is set 323 * AND brokenstop is set
324 * AND no interrupt has been serviced 324 * AND no interrupt has been serviced
325 * we are WD_FREERUN. 325 * we are WD_FREERUN.
326 */ 326 */
@@ -329,7 +329,8 @@ static int cpwd_getstatus(struct cpwd *p, int index)
329 if (p->devs[index].runstatus & WD_STAT_SVCD) { 329 if (p->devs[index].runstatus & WD_STAT_SVCD) {
330 ret = WD_EXPIRED; 330 ret = WD_EXPIRED;
331 } else { 331 } else {
332 /* we could as well pretend we are expired */ 332 /* we could as well pretend
333 * we are expired */
333 ret = WD_FREERUN; 334 ret = WD_FREERUN;
334 } 335 }
335 } else { 336 } else {
@@ -342,7 +343,7 @@ static int cpwd_getstatus(struct cpwd *p, int index)
342 if (p->devs[index].runstatus & WD_STAT_SVCD) 343 if (p->devs[index].runstatus & WD_STAT_SVCD)
343 ret |= WD_SERVICED; 344 ret |= WD_SERVICED;
344 345
345 return(ret); 346 return ret;
346} 347}
347 348
348static irqreturn_t cpwd_interrupt(int irq, void *dev_id) 349static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
@@ -367,22 +368,22 @@ static int cpwd_open(struct inode *inode, struct file *f)
367 struct cpwd *p = cpwd_device; 368 struct cpwd *p = cpwd_device;
368 369
369 lock_kernel(); 370 lock_kernel();
370 switch(iminor(inode)) { 371 switch (iminor(inode)) {
371 case WD0_MINOR: 372 case WD0_MINOR:
372 case WD1_MINOR: 373 case WD1_MINOR:
373 case WD2_MINOR: 374 case WD2_MINOR:
374 break; 375 break;
375 376
376 default: 377 default:
377 unlock_kernel(); 378 unlock_kernel();
378 return -ENODEV; 379 return -ENODEV;
379 } 380 }
380 381
381 /* Register IRQ on first open of device */ 382 /* Register IRQ on first open of device */
382 if (!p->initialized) { 383 if (!p->initialized) {
383 if (request_irq(p->irq, &cpwd_interrupt, 384 if (request_irq(p->irq, &cpwd_interrupt,
384 IRQF_SHARED, DRIVER_NAME, p)) { 385 IRQF_SHARED, DRIVER_NAME, p)) {
385 printk(KERN_ERR PFX "Cannot register IRQ %d\n", 386 printk(KERN_ERR PFX "Cannot register IRQ %d\n",
386 p->irq); 387 p->irq);
387 unlock_kernel(); 388 unlock_kernel();
388 return -EBUSY; 389 return -EBUSY;
@@ -400,8 +401,7 @@ static int cpwd_release(struct inode *inode, struct file *file)
400 return 0; 401 return 0;
401} 402}
402 403
403static int cpwd_ioctl(struct inode *inode, struct file *file, 404static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
404 unsigned int cmd, unsigned long arg)
405{ 405{
406 static struct watchdog_info info = { 406 static struct watchdog_info info = {
407 .options = WDIOF_SETTIMEOUT, 407 .options = WDIOF_SETTIMEOUT,
@@ -409,6 +409,7 @@ static int cpwd_ioctl(struct inode *inode, struct file *file,
409 .identity = DRIVER_NAME, 409 .identity = DRIVER_NAME,
410 }; 410 };
411 void __user *argp = (void __user *)arg; 411 void __user *argp = (void __user *)arg;
412 struct inode *inode = file->f_path.dentry->d_inode;
412 int index = iminor(inode) - WD0_MINOR; 413 int index = iminor(inode) - WD0_MINOR;
413 struct cpwd *p = cpwd_device; 414 struct cpwd *p = cpwd_device;
414 int setopt = 0; 415 int setopt = 0;
@@ -442,7 +443,7 @@ static int cpwd_ioctl(struct inode *inode, struct file *file,
442 cpwd_starttimer(p, index); 443 cpwd_starttimer(p, index);
443 } else { 444 } else {
444 return -EINVAL; 445 return -EINVAL;
445 } 446 }
446 break; 447 break;
447 448
448 /* Solaris-compatible IOCTLs */ 449 /* Solaris-compatible IOCTLs */
@@ -458,7 +459,7 @@ static int cpwd_ioctl(struct inode *inode, struct file *file,
458 459
459 case WIOCSTOP: 460 case WIOCSTOP:
460 if (p->enabled) 461 if (p->enabled)
461 return(-EINVAL); 462 return -EINVAL;
462 463
463 cpwd_stoptimer(p, index); 464 cpwd_stoptimer(p, index);
464 break; 465 break;
@@ -481,7 +482,7 @@ static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
481 case WIOCSTOP: 482 case WIOCSTOP:
482 case WIOCGSTAT: 483 case WIOCGSTAT:
483 lock_kernel(); 484 lock_kernel();
484 rval = cpwd_ioctl(file->f_path.dentry->d_inode, file, cmd, arg); 485 rval = cpwd_ioctl(file, cmd, arg);
485 unlock_kernel(); 486 unlock_kernel();
486 break; 487 break;
487 488
@@ -493,7 +494,7 @@ static long cpwd_compat_ioctl(struct file *file, unsigned int cmd,
493 return rval; 494 return rval;
494} 495}
495 496
496static ssize_t cpwd_write(struct file *file, const char __user *buf, 497static ssize_t cpwd_write(struct file *file, const char __user *buf,
497 size_t count, loff_t *ppos) 498 size_t count, loff_t *ppos)
498{ 499{
499 struct inode *inode = file->f_path.dentry->d_inode; 500 struct inode *inode = file->f_path.dentry->d_inode;
@@ -508,20 +509,20 @@ static ssize_t cpwd_write(struct file *file, const char __user *buf,
508 return 0; 509 return 0;
509} 510}
510 511
511static ssize_t cpwd_read(struct file * file, char __user *buffer, 512static ssize_t cpwd_read(struct file *file, char __user *buffer,
512 size_t count, loff_t *ppos) 513 size_t count, loff_t *ppos)
513{ 514{
514 return -EINVAL; 515 return -EINVAL;
515} 516}
516 517
517static const struct file_operations cpwd_fops = { 518static const struct file_operations cpwd_fops = {
518 .owner = THIS_MODULE, 519 .owner = THIS_MODULE,
519 .ioctl = cpwd_ioctl, 520 .unlocked_ioctl = cpwd_ioctl,
520 .compat_ioctl = cpwd_compat_ioctl, 521 .compat_ioctl = cpwd_compat_ioctl,
521 .open = cpwd_open, 522 .open = cpwd_open,
522 .write = cpwd_write, 523 .write = cpwd_write,
523 .read = cpwd_read, 524 .read = cpwd_read,
524 .release = cpwd_release, 525 .release = cpwd_release,
525}; 526};
526 527
527static int __devinit cpwd_probe(struct of_device *op, 528static int __devinit cpwd_probe(struct of_device *op,