This source file includes following definitions.
- cpwd_writew
- cpwd_readw
- cpwd_writeb
- cpwd_readb
- cpwd_toggleintr
- cpwd_resetbrokentimer
- cpwd_brokentimer
- cpwd_pingtimer
- cpwd_stoptimer
- cpwd_starttimer
- cpwd_getstatus
- cpwd_interrupt
- cpwd_open
- cpwd_release
- cpwd_ioctl
- cpwd_compat_ioctl
- cpwd_write
- cpwd_read
- cpwd_probe
- cpwd_remove
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
19
20 #include <linux/kernel.h>
21 #include <linux/module.h>
22 #include <linux/fs.h>
23 #include <linux/errno.h>
24 #include <linux/major.h>
25 #include <linux/miscdevice.h>
26 #include <linux/interrupt.h>
27 #include <linux/ioport.h>
28 #include <linux/timer.h>
29 #include <linux/compat.h>
30 #include <linux/slab.h>
31 #include <linux/mutex.h>
32 #include <linux/io.h>
33 #include <linux/of.h>
34 #include <linux/of_device.h>
35 #include <linux/uaccess.h>
36
37 #include <asm/irq.h>
38 #include <asm/watchdog.h>
39
40 #define DRIVER_NAME "cpwd"
41
42 #define WD_OBPNAME "watchdog"
43 #define WD_BADMODEL "SUNW,501-5336"
44 #define WD_BTIMEOUT (jiffies + (HZ * 1000))
45 #define WD_BLIMIT 0xFFFF
46
47 #define WD0_MINOR 212
48 #define WD1_MINOR 213
49 #define WD2_MINOR 214
50
51
52 #define WD0_ID 0
53 #define WD1_ID 1
54 #define WD2_ID 2
55 #define WD_NUMDEVS 3
56
57 #define WD_INTR_OFF 0
58 #define WD_INTR_ON 1
59
60 #define WD_STAT_INIT 0x01
61 #define WD_STAT_BSTOP 0x02
62 #define WD_STAT_SVCD 0x04
63
64
65
66 #define WD0_INTR_MASK 0x01
67 #define WD1_INTR_MASK 0x02
68 #define WD2_INTR_MASK 0x04
69
70 #define WD_S_RUNNING 0x01
71 #define WD_S_EXPIRED 0x02
72
73 struct cpwd {
74 void __iomem *regs;
75 spinlock_t lock;
76
77 unsigned int irq;
78
79 unsigned long timeout;
80 bool enabled;
81 bool reboot;
82 bool broken;
83 bool initialized;
84
85 struct {
86 struct miscdevice misc;
87 void __iomem *regs;
88 u8 intr_mask;
89 u8 runstatus;
90 u16 timeout;
91 } devs[WD_NUMDEVS];
92 };
93
94 static DEFINE_MUTEX(cpwd_mutex);
95 static struct cpwd *cpwd_device;
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 #define WD_TIMER_REGSZ 16
147 #define WD0_OFF 0
148 #define WD1_OFF (WD_TIMER_REGSZ * 1)
149 #define WD2_OFF (WD_TIMER_REGSZ * 2)
150 #define PLD_OFF (WD_TIMER_REGSZ * 3)
151
152 #define WD_DCNTR 0x00
153 #define WD_LIMIT 0x04
154 #define WD_STATUS 0x08
155
156 #define PLD_IMASK (PLD_OFF + 0x00)
157 #define PLD_STATUS (PLD_OFF + 0x04)
158
159 static struct timer_list cpwd_timer;
160
161 static int wd0_timeout;
162 static int wd1_timeout;
163 static int wd2_timeout;
164
165 module_param(wd0_timeout, int, 0);
166 MODULE_PARM_DESC(wd0_timeout, "Default watchdog0 timeout in 1/10secs");
167 module_param(wd1_timeout, int, 0);
168 MODULE_PARM_DESC(wd1_timeout, "Default watchdog1 timeout in 1/10secs");
169 module_param(wd2_timeout, int, 0);
170 MODULE_PARM_DESC(wd2_timeout, "Default watchdog2 timeout in 1/10secs");
171
172 MODULE_AUTHOR("Eric Brower <ebrower@usa.net>");
173 MODULE_DESCRIPTION("Hardware watchdog driver for Sun Microsystems CP1400/1500");
174 MODULE_LICENSE("GPL");
175 MODULE_SUPPORTED_DEVICE("watchdog");
176
177 static void cpwd_writew(u16 val, void __iomem *addr)
178 {
179 writew(cpu_to_le16(val), addr);
180 }
181 static u16 cpwd_readw(void __iomem *addr)
182 {
183 u16 val = readw(addr);
184
185 return le16_to_cpu(val);
186 }
187
188 static void cpwd_writeb(u8 val, void __iomem *addr)
189 {
190 writeb(val, addr);
191 }
192
193 static u8 cpwd_readb(void __iomem *addr)
194 {
195 return readb(addr);
196 }
197
198
199
200
201
202
203
204
205 static void cpwd_toggleintr(struct cpwd *p, int index, int enable)
206 {
207 unsigned char curregs = cpwd_readb(p->regs + PLD_IMASK);
208 unsigned char setregs =
209 (index == -1) ?
210 (WD0_INTR_MASK | WD1_INTR_MASK | WD2_INTR_MASK) :
211 (p->devs[index].intr_mask);
212
213 if (enable == WD_INTR_ON)
214 curregs &= ~setregs;
215 else
216 curregs |= setregs;
217
218 cpwd_writeb(curregs, p->regs + PLD_IMASK);
219 }
220
221
222
223
224 static void cpwd_resetbrokentimer(struct cpwd *p, int index)
225 {
226 cpwd_toggleintr(p, index, WD_INTR_ON);
227 cpwd_writew(WD_BLIMIT, p->devs[index].regs + WD_LIMIT);
228 }
229
230
231
232
233
234
235 static void cpwd_brokentimer(struct timer_list *unused)
236 {
237 struct cpwd *p = cpwd_device;
238 int id, tripped = 0;
239
240
241
242
243 if (timer_pending(&cpwd_timer))
244 del_timer(&cpwd_timer);
245
246 for (id = 0; id < WD_NUMDEVS; id++) {
247 if (p->devs[id].runstatus & WD_STAT_BSTOP) {
248 ++tripped;
249 cpwd_resetbrokentimer(p, id);
250 }
251 }
252
253 if (tripped) {
254
255 cpwd_timer.expires = WD_BTIMEOUT;
256 add_timer(&cpwd_timer);
257 }
258 }
259
260
261
262
263 static void cpwd_pingtimer(struct cpwd *p, int index)
264 {
265 if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING)
266 cpwd_readw(p->devs[index].regs + WD_DCNTR);
267 }
268
269
270
271
272
273 static void cpwd_stoptimer(struct cpwd *p, int index)
274 {
275 if (cpwd_readb(p->devs[index].regs + WD_STATUS) & WD_S_RUNNING) {
276 cpwd_toggleintr(p, index, WD_INTR_OFF);
277
278 if (p->broken) {
279 p->devs[index].runstatus |= WD_STAT_BSTOP;
280 cpwd_brokentimer(NULL);
281 }
282 }
283 }
284
285
286
287
288
289
290
291
292 static void cpwd_starttimer(struct cpwd *p, int index)
293 {
294 if (p->broken)
295 p->devs[index].runstatus &= ~WD_STAT_BSTOP;
296
297 p->devs[index].runstatus &= ~WD_STAT_SVCD;
298
299 cpwd_writew(p->devs[index].timeout, p->devs[index].regs + WD_LIMIT);
300 cpwd_toggleintr(p, index, WD_INTR_ON);
301 }
302
303 static int cpwd_getstatus(struct cpwd *p, int index)
304 {
305 unsigned char stat = cpwd_readb(p->devs[index].regs + WD_STATUS);
306 unsigned char intr = cpwd_readb(p->devs[index].regs + PLD_IMASK);
307 unsigned char ret = WD_STOPPED;
308
309
310 if (!stat)
311 return ret;
312
313
314 else if (WD_S_EXPIRED & stat) {
315 ret = WD_EXPIRED;
316 } else if (WD_S_RUNNING & stat) {
317 if (intr & p->devs[index].intr_mask) {
318 ret = WD_FREERUN;
319 } else {
320
321
322
323
324
325
326
327
328
329
330
331 if (p->broken &&
332 (p->devs[index].runstatus & WD_STAT_BSTOP)) {
333 if (p->devs[index].runstatus & WD_STAT_SVCD) {
334 ret = WD_EXPIRED;
335 } else {
336
337
338 ret = WD_FREERUN;
339 }
340 } else {
341 ret = WD_RUNNING;
342 }
343 }
344 }
345
346
347 if (p->devs[index].runstatus & WD_STAT_SVCD)
348 ret |= WD_SERVICED;
349
350 return ret;
351 }
352
353 static irqreturn_t cpwd_interrupt(int irq, void *dev_id)
354 {
355 struct cpwd *p = dev_id;
356
357
358
359
360 spin_lock_irq(&p->lock);
361
362 cpwd_stoptimer(p, WD0_ID);
363 p->devs[WD0_ID].runstatus |= WD_STAT_SVCD;
364
365 spin_unlock_irq(&p->lock);
366
367 return IRQ_HANDLED;
368 }
369
370 static int cpwd_open(struct inode *inode, struct file *f)
371 {
372 struct cpwd *p = cpwd_device;
373
374 mutex_lock(&cpwd_mutex);
375 switch (iminor(inode)) {
376 case WD0_MINOR:
377 case WD1_MINOR:
378 case WD2_MINOR:
379 break;
380
381 default:
382 mutex_unlock(&cpwd_mutex);
383 return -ENODEV;
384 }
385
386
387 if (!p->initialized) {
388 if (request_irq(p->irq, &cpwd_interrupt,
389 IRQF_SHARED, DRIVER_NAME, p)) {
390 pr_err("Cannot register IRQ %d\n", p->irq);
391 mutex_unlock(&cpwd_mutex);
392 return -EBUSY;
393 }
394 p->initialized = true;
395 }
396
397 mutex_unlock(&cpwd_mutex);
398
399 return stream_open(inode, f);
400 }
401
402 static int cpwd_release(struct inode *inode, struct file *file)
403 {
404 return 0;
405 }
406
407 static long cpwd_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
408 {
409 static const struct watchdog_info info = {
410 .options = WDIOF_SETTIMEOUT,
411 .firmware_version = 1,
412 .identity = DRIVER_NAME,
413 };
414 void __user *argp = (void __user *)arg;
415 struct inode *inode = file_inode(file);
416 int index = iminor(inode) - WD0_MINOR;
417 struct cpwd *p = cpwd_device;
418 int setopt = 0;
419
420 switch (cmd) {
421
422 case WDIOC_GETSUPPORT:
423 if (copy_to_user(argp, &info, sizeof(struct watchdog_info)))
424 return -EFAULT;
425 break;
426
427 case WDIOC_GETSTATUS:
428 case WDIOC_GETBOOTSTATUS:
429 if (put_user(0, (int __user *)argp))
430 return -EFAULT;
431 break;
432
433 case WDIOC_KEEPALIVE:
434 cpwd_pingtimer(p, index);
435 break;
436
437 case WDIOC_SETOPTIONS:
438 if (copy_from_user(&setopt, argp, sizeof(unsigned int)))
439 return -EFAULT;
440
441 if (setopt & WDIOS_DISABLECARD) {
442 if (p->enabled)
443 return -EINVAL;
444 cpwd_stoptimer(p, index);
445 } else if (setopt & WDIOS_ENABLECARD) {
446 cpwd_starttimer(p, index);
447 } else {
448 return -EINVAL;
449 }
450 break;
451
452
453 case WIOCGSTAT:
454 setopt = cpwd_getstatus(p, index);
455 if (copy_to_user(argp, &setopt, sizeof(unsigned int)))
456 return -EFAULT;
457 break;
458
459 case WIOCSTART:
460 cpwd_starttimer(p, index);
461 break;
462
463 case WIOCSTOP:
464 if (p->enabled)
465 return -EINVAL;
466
467 cpwd_stoptimer(p, index);
468 break;
469
470 default:
471 return -EINVAL;
472 }
473
474 return 0;
475 }
476
477 static long cpwd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
478 {
479 return cpwd_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
480 }
481
482 static ssize_t cpwd_write(struct file *file, const char __user *buf,
483 size_t count, loff_t *ppos)
484 {
485 struct inode *inode = file_inode(file);
486 struct cpwd *p = cpwd_device;
487 int index = iminor(inode);
488
489 if (count) {
490 cpwd_pingtimer(p, index);
491 return 1;
492 }
493
494 return 0;
495 }
496
497 static ssize_t cpwd_read(struct file *file, char __user *buffer,
498 size_t count, loff_t *ppos)
499 {
500 return -EINVAL;
501 }
502
503 static const struct file_operations cpwd_fops = {
504 .owner = THIS_MODULE,
505 .unlocked_ioctl = cpwd_ioctl,
506 .compat_ioctl = cpwd_compat_ioctl,
507 .open = cpwd_open,
508 .write = cpwd_write,
509 .read = cpwd_read,
510 .release = cpwd_release,
511 .llseek = no_llseek,
512 };
513
514 static int cpwd_probe(struct platform_device *op)
515 {
516 struct device_node *options;
517 const char *str_prop;
518 const void *prop_val;
519 int i, err = -EINVAL;
520 struct cpwd *p;
521
522 if (cpwd_device)
523 return -EINVAL;
524
525 p = devm_kzalloc(&op->dev, sizeof(*p), GFP_KERNEL);
526 if (!p)
527 return -ENOMEM;
528
529 p->irq = op->archdata.irqs[0];
530
531 spin_lock_init(&p->lock);
532
533 p->regs = of_ioremap(&op->resource[0], 0,
534 4 * WD_TIMER_REGSZ, DRIVER_NAME);
535 if (!p->regs) {
536 pr_err("Unable to map registers\n");
537 return -ENOMEM;
538 }
539
540 options = of_find_node_by_path("/options");
541 if (!options) {
542 err = -ENODEV;
543 pr_err("Unable to find /options node\n");
544 goto out_iounmap;
545 }
546
547 prop_val = of_get_property(options, "watchdog-enable?", NULL);
548 p->enabled = (prop_val ? true : false);
549
550 prop_val = of_get_property(options, "watchdog-reboot?", NULL);
551 p->reboot = (prop_val ? true : false);
552
553 str_prop = of_get_property(options, "watchdog-timeout", NULL);
554 if (str_prop)
555 p->timeout = simple_strtoul(str_prop, NULL, 10);
556
557 of_node_put(options);
558
559
560
561
562
563 str_prop = of_get_property(op->dev.of_node, "model", NULL);
564 p->broken = (str_prop && !strcmp(str_prop, WD_BADMODEL));
565
566 if (!p->enabled)
567 cpwd_toggleintr(p, -1, WD_INTR_OFF);
568
569 for (i = 0; i < WD_NUMDEVS; i++) {
570 static const char *cpwd_names[] = { "RIC", "XIR", "POR" };
571 static int *parms[] = { &wd0_timeout,
572 &wd1_timeout,
573 &wd2_timeout };
574 struct miscdevice *mp = &p->devs[i].misc;
575
576 mp->minor = WD0_MINOR + i;
577 mp->name = cpwd_names[i];
578 mp->fops = &cpwd_fops;
579
580 p->devs[i].regs = p->regs + (i * WD_TIMER_REGSZ);
581 p->devs[i].intr_mask = (WD0_INTR_MASK << i);
582 p->devs[i].runstatus &= ~WD_STAT_BSTOP;
583 p->devs[i].runstatus |= WD_STAT_INIT;
584 p->devs[i].timeout = p->timeout;
585 if (*parms[i])
586 p->devs[i].timeout = *parms[i];
587
588 err = misc_register(&p->devs[i].misc);
589 if (err) {
590 pr_err("Could not register misc device for dev %d\n",
591 i);
592 goto out_unregister;
593 }
594 }
595
596 if (p->broken) {
597 timer_setup(&cpwd_timer, cpwd_brokentimer, 0);
598 cpwd_timer.expires = WD_BTIMEOUT;
599
600 pr_info("PLD defect workaround enabled for model %s\n",
601 WD_BADMODEL);
602 }
603
604 platform_set_drvdata(op, p);
605 cpwd_device = p;
606 return 0;
607
608 out_unregister:
609 for (i--; i >= 0; i--)
610 misc_deregister(&p->devs[i].misc);
611
612 out_iounmap:
613 of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
614
615 return err;
616 }
617
618 static int cpwd_remove(struct platform_device *op)
619 {
620 struct cpwd *p = platform_get_drvdata(op);
621 int i;
622
623 for (i = 0; i < WD_NUMDEVS; i++) {
624 misc_deregister(&p->devs[i].misc);
625
626 if (!p->enabled) {
627 cpwd_stoptimer(p, i);
628 if (p->devs[i].runstatus & WD_STAT_BSTOP)
629 cpwd_resetbrokentimer(p, i);
630 }
631 }
632
633 if (p->broken)
634 del_timer_sync(&cpwd_timer);
635
636 if (p->initialized)
637 free_irq(p->irq, p);
638
639 of_iounmap(&op->resource[0], p->regs, 4 * WD_TIMER_REGSZ);
640
641 cpwd_device = NULL;
642
643 return 0;
644 }
645
646 static const struct of_device_id cpwd_match[] = {
647 {
648 .name = "watchdog",
649 },
650 {},
651 };
652 MODULE_DEVICE_TABLE(of, cpwd_match);
653
654 static struct platform_driver cpwd_driver = {
655 .driver = {
656 .name = DRIVER_NAME,
657 .of_match_table = cpwd_match,
658 },
659 .probe = cpwd_probe,
660 .remove = cpwd_remove,
661 };
662
663 module_platform_driver(cpwd_driver);