1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
41
42#include <linux/interrupt.h>
43#include <linux/module.h>
44#include <linux/moduleparam.h>
45#include <linux/types.h>
46#include <linux/miscdevice.h>
47#include <linux/watchdog.h>
48#include <linux/ioport.h>
49#include <linux/delay.h>
50#include <linux/notifier.h>
51#include <linux/reboot.h>
52#include <linux/fs.h>
53#include <linux/pci.h>
54#include <linux/io.h>
55#include <linux/uaccess.h>
56
57
58#define WDT_IS_PCI
59#include "wd501p.h"
60
61
62static int dev_count;
63
64static unsigned long open_lock;
65static DEFINE_SPINLOCK(wdtpci_lock);
66static char expect_close;
67
68static resource_size_t io;
69static int irq;
70
71
72#define WD_TIMO 60
73
74static int heartbeat = WD_TIMO;
75static int wd_heartbeat;
76module_param(heartbeat, int, 0);
77MODULE_PARM_DESC(heartbeat,
78 "Watchdog heartbeat in seconds. (0<heartbeat<65536, default="
79 __MODULE_STRING(WD_TIMO) ")");
80
81static bool nowayout = WATCHDOG_NOWAYOUT;
82module_param(nowayout, bool, 0);
83MODULE_PARM_DESC(nowayout,
84 "Watchdog cannot be stopped once started (default="
85 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
86
87
88static int tachometer;
89module_param(tachometer, int, 0);
90MODULE_PARM_DESC(tachometer,
91 "PCI-WDT501 Fan Tachometer support (0=disable, default=0)");
92
93static int type = 500;
94module_param(type, int, 0);
95MODULE_PARM_DESC(type,
96 "PCI-WDT501 Card type (500 or 501 , default=500)");
97
98
99
100
101
102static void wdtpci_ctr_mode(int ctr, int mode)
103{
104 ctr <<= 6;
105 ctr |= 0x30;
106 ctr |= (mode << 1);
107 outb(ctr, WDT_CR);
108 udelay(8);
109}
110
111static void wdtpci_ctr_load(int ctr, int val)
112{
113 outb(val & 0xFF, WDT_COUNT0 + ctr);
114 udelay(8);
115 outb(val >> 8, WDT_COUNT0 + ctr);
116 udelay(8);
117}
118
119
120
121
122
123
124
125static int wdtpci_start(void)
126{
127 unsigned long flags;
128
129 spin_lock_irqsave(&wdtpci_lock, flags);
130
131
132
133
134
135 inb(WDT_DC);
136 udelay(8);
137 wdtpci_ctr_mode(2, 0);
138
139 outb(0, WDT_DC);
140 udelay(8);
141 inb(WDT_DC);
142 udelay(8);
143 outb(0, WDT_CLOCK);
144 udelay(8);
145 inb(WDT_BUZZER);
146 udelay(8);
147 inb(WDT_OPTONOTRST);
148 udelay(8);
149 inb(WDT_OPTORST);
150 udelay(8);
151 inb(WDT_PROGOUT);
152 udelay(8);
153 wdtpci_ctr_mode(0, 3);
154
155 wdtpci_ctr_mode(1, 2);
156
157 wdtpci_ctr_mode(2, 1);
158
159 wdtpci_ctr_load(0, 20833);
160 wdtpci_ctr_load(1, wd_heartbeat);
161
162 outb(0, WDT_DC);
163 udelay(8);
164
165 spin_unlock_irqrestore(&wdtpci_lock, flags);
166 return 0;
167}
168
169
170
171
172
173
174
175static int wdtpci_stop(void)
176{
177 unsigned long flags;
178
179
180 spin_lock_irqsave(&wdtpci_lock, flags);
181 inb(WDT_DC);
182 udelay(8);
183 wdtpci_ctr_load(2, 0);
184 spin_unlock_irqrestore(&wdtpci_lock, flags);
185 return 0;
186}
187
188
189
190
191
192
193
194
195static int wdtpci_ping(void)
196{
197 unsigned long flags;
198
199 spin_lock_irqsave(&wdtpci_lock, flags);
200
201 inb(WDT_DC);
202 udelay(8);
203 wdtpci_ctr_mode(1, 2);
204
205 wdtpci_ctr_load(1, wd_heartbeat);
206 outb(0, WDT_DC);
207 udelay(8);
208 spin_unlock_irqrestore(&wdtpci_lock, flags);
209 return 0;
210}
211
212
213
214
215
216
217
218
219
220static int wdtpci_set_heartbeat(int t)
221{
222
223 if (t < 1 || t > 65535)
224 return -EINVAL;
225
226 heartbeat = t;
227 wd_heartbeat = t * 100;
228 return 0;
229}
230
231
232
233
234
235
236
237
238
239
240
241
242static int wdtpci_get_status(int *status)
243{
244 unsigned char new_status;
245 unsigned long flags;
246
247 spin_lock_irqsave(&wdtpci_lock, flags);
248 new_status = inb(WDT_SR);
249 spin_unlock_irqrestore(&wdtpci_lock, flags);
250
251 *status = 0;
252 if (new_status & WDC_SR_ISOI0)
253 *status |= WDIOF_EXTERN1;
254 if (new_status & WDC_SR_ISII1)
255 *status |= WDIOF_EXTERN2;
256 if (type == 501) {
257 if (!(new_status & WDC_SR_TGOOD))
258 *status |= WDIOF_OVERHEAT;
259 if (!(new_status & WDC_SR_PSUOVER))
260 *status |= WDIOF_POWEROVER;
261 if (!(new_status & WDC_SR_PSUUNDR))
262 *status |= WDIOF_POWERUNDER;
263 if (tachometer) {
264 if (!(new_status & WDC_SR_FANGOOD))
265 *status |= WDIOF_FANFAULT;
266 }
267 }
268 return 0;
269}
270
271
272
273
274
275
276
277
278static int wdtpci_get_temperature(int *temperature)
279{
280 unsigned short c;
281 unsigned long flags;
282 spin_lock_irqsave(&wdtpci_lock, flags);
283 c = inb(WDT_RT);
284 udelay(8);
285 spin_unlock_irqrestore(&wdtpci_lock, flags);
286 *temperature = (c * 11 / 15) + 7;
287 return 0;
288}
289
290
291
292
293
294
295
296
297
298
299
300static irqreturn_t wdtpci_interrupt(int irq, void *dev_id)
301{
302
303
304
305
306 unsigned char status;
307
308 spin_lock(&wdtpci_lock);
309
310 status = inb(WDT_SR);
311 udelay(8);
312
313 pr_crit("status %d\n", status);
314
315 if (type == 501) {
316 if (!(status & WDC_SR_TGOOD)) {
317 pr_crit("Overheat alarm (%d)\n", inb(WDT_RT));
318 udelay(8);
319 }
320 if (!(status & WDC_SR_PSUOVER))
321 pr_crit("PSU over voltage\n");
322 if (!(status & WDC_SR_PSUUNDR))
323 pr_crit("PSU under voltage\n");
324 if (tachometer) {
325 if (!(status & WDC_SR_FANGOOD))
326 pr_crit("Possible fan fault\n");
327 }
328 }
329 if (!(status & WDC_SR_WCCR)) {
330#ifdef SOFTWARE_REBOOT
331#ifdef ONLY_TESTING
332 pr_crit("Would Reboot\n");
333#else
334 pr_crit("Initiating system reboot\n");
335 emergency_restart();
336#endif
337#else
338 pr_crit("Reset in 5ms\n");
339#endif
340 }
341 spin_unlock(&wdtpci_lock);
342 return IRQ_HANDLED;
343}
344
345
346
347
348
349
350
351
352
353
354
355
356
357static ssize_t wdtpci_write(struct file *file, const char __user *buf,
358 size_t count, loff_t *ppos)
359{
360 if (count) {
361 if (!nowayout) {
362 size_t i;
363
364
365 expect_close = 0;
366
367 for (i = 0; i != count; i++) {
368 char c;
369 if (get_user(c, buf + i))
370 return -EFAULT;
371 if (c == 'V')
372 expect_close = 42;
373 }
374 }
375 wdtpci_ping();
376 }
377 return count;
378}
379
380
381
382
383
384
385
386
387
388
389
390
391static long wdtpci_ioctl(struct file *file, unsigned int cmd,
392 unsigned long arg)
393{
394 void __user *argp = (void __user *)arg;
395 int __user *p = argp;
396 int new_heartbeat;
397 int status;
398
399 struct watchdog_info ident = {
400 .options = WDIOF_SETTIMEOUT|
401 WDIOF_MAGICCLOSE|
402 WDIOF_KEEPALIVEPING,
403 .firmware_version = 1,
404 .identity = "PCI-WDT500/501",
405 };
406
407
408 ident.options |= (WDIOF_EXTERN1|WDIOF_EXTERN2);
409 if (type == 501) {
410 ident.options |= (WDIOF_OVERHEAT|WDIOF_POWERUNDER|
411 WDIOF_POWEROVER);
412 if (tachometer)
413 ident.options |= WDIOF_FANFAULT;
414 }
415
416 switch (cmd) {
417 case WDIOC_GETSUPPORT:
418 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
419 case WDIOC_GETSTATUS:
420 wdtpci_get_status(&status);
421 return put_user(status, p);
422 case WDIOC_GETBOOTSTATUS:
423 return put_user(0, p);
424 case WDIOC_KEEPALIVE:
425 wdtpci_ping();
426 return 0;
427 case WDIOC_SETTIMEOUT:
428 if (get_user(new_heartbeat, p))
429 return -EFAULT;
430 if (wdtpci_set_heartbeat(new_heartbeat))
431 return -EINVAL;
432 wdtpci_ping();
433
434 case WDIOC_GETTIMEOUT:
435 return put_user(heartbeat, p);
436 default:
437 return -ENOTTY;
438 }
439}
440
441
442
443
444
445
446
447
448
449
450
451
452
453static int wdtpci_open(struct inode *inode, struct file *file)
454{
455 if (test_and_set_bit(0, &open_lock))
456 return -EBUSY;
457
458 if (nowayout)
459 __module_get(THIS_MODULE);
460
461
462
463 wdtpci_start();
464 return nonseekable_open(inode, file);
465}
466
467
468
469
470
471
472
473
474
475
476
477
478
479static int wdtpci_release(struct inode *inode, struct file *file)
480{
481 if (expect_close == 42) {
482 wdtpci_stop();
483 } else {
484 pr_crit("Unexpected close, not stopping timer!\n");
485 wdtpci_ping();
486 }
487 expect_close = 0;
488 clear_bit(0, &open_lock);
489 return 0;
490}
491
492
493
494
495
496
497
498
499
500
501
502
503static ssize_t wdtpci_temp_read(struct file *file, char __user *buf,
504 size_t count, loff_t *ptr)
505{
506 int temperature;
507
508 if (wdtpci_get_temperature(&temperature))
509 return -EFAULT;
510
511 if (copy_to_user(buf, &temperature, 1))
512 return -EFAULT;
513
514 return 1;
515}
516
517
518
519
520
521
522
523
524
525static int wdtpci_temp_open(struct inode *inode, struct file *file)
526{
527 return nonseekable_open(inode, file);
528}
529
530
531
532
533
534
535
536
537
538static int wdtpci_temp_release(struct inode *inode, struct file *file)
539{
540 return 0;
541}
542
543
544
545
546
547
548
549
550
551
552
553
554
555static int wdtpci_notify_sys(struct notifier_block *this, unsigned long code,
556 void *unused)
557{
558 if (code == SYS_DOWN || code == SYS_HALT)
559 wdtpci_stop();
560 return NOTIFY_DONE;
561}
562
563
564
565
566
567
568static const struct file_operations wdtpci_fops = {
569 .owner = THIS_MODULE,
570 .llseek = no_llseek,
571 .write = wdtpci_write,
572 .unlocked_ioctl = wdtpci_ioctl,
573 .open = wdtpci_open,
574 .release = wdtpci_release,
575};
576
577static struct miscdevice wdtpci_miscdev = {
578 .minor = WATCHDOG_MINOR,
579 .name = "watchdog",
580 .fops = &wdtpci_fops,
581};
582
583static const struct file_operations wdtpci_temp_fops = {
584 .owner = THIS_MODULE,
585 .llseek = no_llseek,
586 .read = wdtpci_temp_read,
587 .open = wdtpci_temp_open,
588 .release = wdtpci_temp_release,
589};
590
591static struct miscdevice temp_miscdev = {
592 .minor = TEMP_MINOR,
593 .name = "temperature",
594 .fops = &wdtpci_temp_fops,
595};
596
597
598
599
600
601
602static struct notifier_block wdtpci_notifier = {
603 .notifier_call = wdtpci_notify_sys,
604};
605
606
607static int wdtpci_init_one(struct pci_dev *dev,
608 const struct pci_device_id *ent)
609{
610 int ret = -EIO;
611
612 dev_count++;
613 if (dev_count > 1) {
614 pr_err("This driver only supports one device\n");
615 return -ENODEV;
616 }
617
618 if (type != 500 && type != 501) {
619 pr_err("unknown card type '%d'\n", type);
620 return -ENODEV;
621 }
622
623 if (pci_enable_device(dev)) {
624 pr_err("Not possible to enable PCI Device\n");
625 return -ENODEV;
626 }
627
628 if (pci_resource_start(dev, 2) == 0x0000) {
629 pr_err("No I/O-Address for card detected\n");
630 ret = -ENODEV;
631 goto out_pci;
632 }
633
634 if (pci_request_region(dev, 2, "wdt_pci")) {
635 pr_err("I/O address 0x%llx already in use\n",
636 (unsigned long long)pci_resource_start(dev, 2));
637 goto out_pci;
638 }
639
640 irq = dev->irq;
641 io = pci_resource_start(dev, 2);
642
643 if (request_irq(irq, wdtpci_interrupt, IRQF_SHARED,
644 "wdt_pci", &wdtpci_miscdev)) {
645 pr_err("IRQ %d is not free\n", irq);
646 goto out_reg;
647 }
648
649 pr_info("PCI-WDT500/501 (PCI-WDG-CSM) driver 0.10 at 0x%llx (Interrupt %d)\n",
650 (unsigned long long)io, irq);
651
652
653
654 if (wdtpci_set_heartbeat(heartbeat)) {
655 wdtpci_set_heartbeat(WD_TIMO);
656 pr_info("heartbeat value must be 0 < heartbeat < 65536, using %d\n",
657 WD_TIMO);
658 }
659
660 ret = register_reboot_notifier(&wdtpci_notifier);
661 if (ret) {
662 pr_err("cannot register reboot notifier (err=%d)\n", ret);
663 goto out_irq;
664 }
665
666 if (type == 501) {
667 ret = misc_register(&temp_miscdev);
668 if (ret) {
669 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
670 TEMP_MINOR, ret);
671 goto out_rbt;
672 }
673 }
674
675 ret = misc_register(&wdtpci_miscdev);
676 if (ret) {
677 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
678 WATCHDOG_MINOR, ret);
679 goto out_misc;
680 }
681
682 pr_info("initialized. heartbeat=%d sec (nowayout=%d)\n",
683 heartbeat, nowayout);
684 if (type == 501)
685 pr_info("Fan Tachometer is %s\n",
686 tachometer ? "Enabled" : "Disabled");
687
688 ret = 0;
689out:
690 return ret;
691
692out_misc:
693 if (type == 501)
694 misc_deregister(&temp_miscdev);
695out_rbt:
696 unregister_reboot_notifier(&wdtpci_notifier);
697out_irq:
698 free_irq(irq, &wdtpci_miscdev);
699out_reg:
700 pci_release_region(dev, 2);
701out_pci:
702 pci_disable_device(dev);
703 goto out;
704}
705
706
707static void wdtpci_remove_one(struct pci_dev *pdev)
708{
709
710
711 misc_deregister(&wdtpci_miscdev);
712 if (type == 501)
713 misc_deregister(&temp_miscdev);
714 unregister_reboot_notifier(&wdtpci_notifier);
715 free_irq(irq, &wdtpci_miscdev);
716 pci_release_region(pdev, 2);
717 pci_disable_device(pdev);
718 dev_count--;
719}
720
721
722static const struct pci_device_id wdtpci_pci_tbl[] = {
723 {
724 .vendor = PCI_VENDOR_ID_ACCESSIO,
725 .device = PCI_DEVICE_ID_ACCESSIO_WDG_CSM,
726 .subvendor = PCI_ANY_ID,
727 .subdevice = PCI_ANY_ID,
728 },
729 { 0, },
730};
731MODULE_DEVICE_TABLE(pci, wdtpci_pci_tbl);
732
733
734static struct pci_driver wdtpci_driver = {
735 .name = "wdt_pci",
736 .id_table = wdtpci_pci_tbl,
737 .probe = wdtpci_init_one,
738 .remove = wdtpci_remove_one,
739};
740
741module_pci_driver(wdtpci_driver);
742
743MODULE_AUTHOR("JP Nollmann, Alan Cox");
744MODULE_DESCRIPTION("Driver for the ICS PCI-WDT500/501 watchdog cards");
745MODULE_LICENSE("GPL");
746