diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/watchdog/cpwd.c | 78 |
1 files changed, 40 insertions, 38 deletions
diff --git a/drivers/watchdog/cpwd.c b/drivers/watchdog/cpwd.c index 261790afd65b..0c14586f58d4 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) |
@@ -43,8 +43,8 @@ | |||
43 | #define WD_BLIMIT 0xFFFF | 43 | #define WD_BLIMIT 0xFFFF |
44 | 44 | ||
45 | #define WD0_MINOR 212 | 45 | #define WD0_MINOR 212 |
46 | #define WD1_MINOR 213 | 46 | #define WD1_MINOR 213 |
47 | #define WD2_MINOR 214 | 47 | #define WD2_MINOR 214 |
48 | 48 | ||
49 | /* Internal driver definitions. */ | 49 | /* Internal driver definitions. */ |
50 | #define WD0_ID 0 | 50 | #define WD0_ID 0 |
@@ -91,16 +91,16 @@ struct cpwd { | |||
91 | 91 | ||
92 | static struct cpwd *cpwd_device; | 92 | static struct cpwd *cpwd_device; |
93 | 93 | ||
94 | /* Sun uses Altera PLD EPF8820ATC144-4 | 94 | /* Sun uses Altera PLD EPF8820ATC144-4 |
95 | * providing three hardware watchdogs: | 95 | * providing three hardware watchdogs: |
96 | * | 96 | * |
97 | * 1) RIC - sends an interrupt when triggered | 97 | * 1) RIC - sends an interrupt when triggered |
98 | * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU | 98 | * 2) XIR - asserts XIR_B_RESET when triggered, resets CPU |
99 | * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board | 99 | * 3) POR - asserts POR_B_RESET when triggered, resets CPU, backplane, board |
100 | * | 100 | * |
101 | *** Timer register block definition (struct wd_timer_regblk) | 101 | *** Timer register block definition (struct wd_timer_regblk) |
102 | * | 102 | * |
103 | * dcntr and limit registers (halfword access): | 103 | * dcntr and limit registers (halfword access): |
104 | * ------------------- | 104 | * ------------------- |
105 | * | 15 | ...| 1 | 0 | | 105 | * | 15 | ...| 1 | 0 | |
106 | * ------------------- | 106 | * ------------------- |
@@ -108,7 +108,8 @@ static struct cpwd *cpwd_device; | |||
108 | * ------------------- | 108 | * ------------------- |
109 | * dcntr - Current 16-bit downcounter value. | 109 | * dcntr - Current 16-bit downcounter value. |
110 | * When downcounter reaches '0' watchdog expires. | 110 | * When downcounter reaches '0' watchdog expires. |
111 | * Reading this register resets downcounter with 'limit' value. | 111 | * Reading this register resets downcounter with |
112 | * 'limit' value. | ||
112 | * limit - 16-bit countdown value in 1/10th second increments. | 113 | * limit - 16-bit countdown value in 1/10th second increments. |
113 | * Writing this register begins countdown with input value. | 114 | * Writing this register begins countdown with input value. |
114 | * Reading from this register does not affect counter. | 115 | * Reading from this register does not affect counter. |
@@ -158,11 +159,11 @@ static int wd0_timeout = 0; | |||
158 | static int wd1_timeout = 0; | 159 | static int wd1_timeout = 0; |
159 | static int wd2_timeout = 0; | 160 | static int wd2_timeout = 0; |
160 | 161 | ||
161 | module_param (wd0_timeout, int, 0); | 162 | module_param(wd0_timeout, int, 0); |
162 | MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); | 163 | MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs"); |
163 | module_param (wd1_timeout, int, 0); | 164 | module_param(wd1_timeout, int, 0); |
164 | MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); | 165 | MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs"); |
165 | module_param (wd2_timeout, int, 0); | 166 | module_param(wd2_timeout, int, 0); |
166 | MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); | 167 | MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs"); |
167 | 168 | ||
168 | MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); | 169 | MODULE_AUTHOR("Eric Brower <ebrower@usa.net>"); |
@@ -201,9 +202,9 @@ static u8 cpwd_readb(void __iomem *addr) | |||
201 | static void cpwd_toggleintr(struct cpwd *p, int index, int enable) | 202 | static void cpwd_toggleintr(struct cpwd *p, int index, int enable) |
202 | { | 203 | { |
203 | unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); | 204 | unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK); |
204 | unsigned char setregs = | 205 | unsigned char setregs = |
205 | (index == -1) ? | 206 | (index == -1) ? |
206 | (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : | 207 | (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) : |
207 | (p->devs[index].intr_mask); | 208 | (p->devs[index].intr_mask); |
208 | 209 | ||
209 | if (enable == WD_INTR_ON) | 210 | if (enable == WD_INTR_ON) |
@@ -303,24 +304,24 @@ static int cpwd_getstatus(struct cpwd *p, int index) | |||
303 | unsigned char ret = WD_STOPPED; | 304 | unsigned char ret = WD_STOPPED; |
304 | 305 | ||
305 | /* determine STOPPED */ | 306 | /* determine STOPPED */ |
306 | if (!stat) | 307 | if (!stat) |
307 | return ret; | 308 | return ret; |
308 | 309 | ||
309 | /* determine EXPIRED vs FREERUN vs RUNNING */ | 310 | /* determine EXPIRED vs FREERUN vs RUNNING */ |
310 | else if (WD_S_EXPIRED & stat) { | 311 | else if (WD_S_EXPIRED & stat) { |
311 | ret = WD_EXPIRED; | 312 | ret = WD_EXPIRED; |
312 | } else if(WD_S_RUNNING & stat) { | 313 | } else if (WD_S_RUNNING & stat) { |
313 | if (intr & p->devs[index].intr_mask) { | 314 | if (intr & p->devs[index].intr_mask) { |
314 | ret = WD_FREERUN; | 315 | ret = WD_FREERUN; |
315 | } else { | 316 | } else { |
316 | /* Fudge WD_EXPIRED status for defective CP1400-- | 317 | /* Fudge WD_EXPIRED status for defective CP1400-- |
317 | * IF timer is running | 318 | * IF timer is running |
318 | * AND brokenstop is set | 319 | * AND brokenstop is set |
319 | * AND an interrupt has been serviced | 320 | * AND an interrupt has been serviced |
320 | * we are WD_EXPIRED. | 321 | * we are WD_EXPIRED. |
321 | * | 322 | * |
322 | * IF timer is running | 323 | * IF timer is running |
323 | * AND brokenstop is set | 324 | * AND brokenstop is set |
324 | * AND no interrupt has been serviced | 325 | * AND no interrupt has been serviced |
325 | * we are WD_FREERUN. | 326 | * we are WD_FREERUN. |
326 | */ | 327 | */ |
@@ -329,7 +330,8 @@ static int cpwd_getstatus(struct cpwd *p, int index) | |||
329 | if (p->devs[index].runstatus & WD_STAT_SVCD) { | 330 | if (p->devs[index].runstatus & WD_STAT_SVCD) { |
330 | ret = WD_EXPIRED; | 331 | ret = WD_EXPIRED; |
331 | } else { | 332 | } else { |
332 | /* we could as well pretend we are expired */ | 333 | /* we could as well pretend |
334 | * we are expired */ | ||
333 | ret = WD_FREERUN; | 335 | ret = WD_FREERUN; |
334 | } | 336 | } |
335 | } else { | 337 | } else { |
@@ -342,7 +344,7 @@ static int cpwd_getstatus(struct cpwd *p, int index) | |||
342 | if (p->devs[index].runstatus & WD_STAT_SVCD) | 344 | if (p->devs[index].runstatus & WD_STAT_SVCD) |
343 | ret |= WD_SERVICED; | 345 | ret |= WD_SERVICED; |
344 | 346 | ||
345 | return(ret); | 347 | return ret; |
346 | } | 348 | } |
347 | 349 | ||
348 | static irqreturn_t cpwd_interrupt(int irq, void *dev_id) | 350 | static irqreturn_t cpwd_interrupt(int irq, void *dev_id) |
@@ -367,22 +369,22 @@ static int cpwd_open(struct inode *inode, struct file *f) | |||
367 | struct cpwd *p = cpwd_device; | 369 | struct cpwd *p = cpwd_device; |
368 | 370 | ||
369 | lock_kernel(); | 371 | lock_kernel(); |
370 | switch(iminor(inode)) { | 372 | switch (iminor(inode)) { |
371 | case WD0_MINOR: | 373 | case WD0_MINOR: |
372 | case WD1_MINOR: | 374 | case WD1_MINOR: |
373 | case WD2_MINOR: | 375 | case WD2_MINOR: |
374 | break; | 376 | break; |
375 | 377 | ||
376 | default: | 378 | default: |
377 | unlock_kernel(); | 379 | unlock_kernel(); |
378 | return -ENODEV; | 380 | return -ENODEV; |
379 | } | 381 | } |
380 | 382 | ||
381 | /* Register IRQ on first open of device */ | 383 | /* Register IRQ on first open of device */ |
382 | if (!p->initialized) { | 384 | if (!p->initialized) { |
383 | if (request_irq(p->irq, &cpwd_interrupt, | 385 | if (request_irq(p->irq, &cpwd_interrupt, |
384 | IRQF_SHARED, DRIVER_NAME, p)) { | 386 | IRQF_SHARED, DRIVER_NAME, p)) { |
385 | printk(KERN_ERR PFX "Cannot register IRQ %d\n", | 387 | printk(KERN_ERR PFX "Cannot register IRQ %d\n", |
386 | p->irq); | 388 | p->irq); |
387 | unlock_kernel(); | 389 | unlock_kernel(); |
388 | return -EBUSY; | 390 | return -EBUSY; |
@@ -442,7 +444,7 @@ static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
442 | cpwd_starttimer(p, index); | 444 | cpwd_starttimer(p, index); |
443 | } else { | 445 | } else { |
444 | return -EINVAL; | 446 | return -EINVAL; |
445 | } | 447 | } |
446 | break; | 448 | break; |
447 | 449 | ||
448 | /* Solaris-compatible IOCTLs */ | 450 | /* Solaris-compatible IOCTLs */ |
@@ -458,7 +460,7 @@ static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | |||
458 | 460 | ||
459 | case WIOCSTOP: | 461 | case WIOCSTOP: |
460 | if (p->enabled) | 462 | if (p->enabled) |
461 | return(-EINVAL); | 463 | return -EINVAL; |
462 | 464 | ||
463 | cpwd_stoptimer(p, index); | 465 | cpwd_stoptimer(p, index); |
464 | break; | 466 | break; |
@@ -493,7 +495,7 @@ static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, | |||
493 | return rval; | 495 | return rval; |
494 | } | 496 | } |
495 | 497 | ||
496 | static ssize_t cpwd_write(struct file *file, const char __user *buf, | 498 | static ssize_t cpwd_write(struct file *file, const char __user *buf, |
497 | size_t count, loff_t *ppos) | 499 | size_t count, loff_t *ppos) |
498 | { | 500 | { |
499 | struct inode *inode = file->f_path.dentry->d_inode; | 501 | struct inode *inode = file->f_path.dentry->d_inode; |
@@ -508,7 +510,7 @@ static ssize_t cpwd_write(struct file *file, const char __user *buf, | |||
508 | return 0; | 510 | return 0; |
509 | } | 511 | } |
510 | 512 | ||
511 | static ssize_t cpwd_read(struct file * file, char __user *buffer, | 513 | static ssize_t cpwd_read(struct file *file, char __user *buffer, |
512 | size_t count, loff_t *ppos) | 514 | size_t count, loff_t *ppos) |
513 | { | 515 | { |
514 | return -EINVAL; | 516 | return -EINVAL; |