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#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
30
31#include <linux/fs.h>
32#include <linux/init.h>
33#include <linux/kernel.h>
34#include <linux/miscdevice.h>
35#include <linux/module.h>
36#include <linux/notifier.h>
37#include <linux/reboot.h>
38#include <linux/types.h>
39#include <linux/watchdog.h>
40#include <linux/uaccess.h>
41
42#include <asm/rtas.h>
43
44#define WDRTAS_MAGIC_CHAR 42
45#define WDRTAS_SUPPORTED_MASK (WDIOF_SETTIMEOUT | \
46 WDIOF_MAGICCLOSE)
47
48MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
49MODULE_DESCRIPTION("RTAS watchdog driver");
50MODULE_LICENSE("GPL");
51MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
52MODULE_ALIAS_MISCDEV(TEMP_MINOR);
53
54static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
55static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
56static char wdrtas_expect_close;
57
58static int wdrtas_interval;
59
60#define WDRTAS_THERMAL_SENSOR 3
61static int wdrtas_token_get_sensor_state;
62#define WDRTAS_SURVEILLANCE_IND 9000
63static int wdrtas_token_set_indicator;
64#define WDRTAS_SP_SPI 28
65static int wdrtas_token_get_sp;
66static int wdrtas_token_event_scan;
67
68#define WDRTAS_DEFAULT_INTERVAL 300
69
70#define WDRTAS_LOGBUFFER_LEN 128
71static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87static int wdrtas_set_interval(int interval)
88{
89 long result;
90 static int print_msg = 10;
91
92
93 interval = (interval + 59) / 60;
94
95 result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
96 WDRTAS_SURVEILLANCE_IND, 0, interval);
97 if (result < 0 && print_msg) {
98 pr_err("setting the watchdog to %i timeout failed: %li\n",
99 interval, result);
100 print_msg--;
101 }
102
103 return result;
104}
105
106#define WDRTAS_SP_SPI_LEN 4
107
108
109
110
111
112
113
114
115
116
117
118static int wdrtas_get_interval(int fallback_value)
119{
120 long result;
121 char value[WDRTAS_SP_SPI_LEN];
122
123 spin_lock(&rtas_data_buf_lock);
124 memset(rtas_data_buf, 0, WDRTAS_SP_SPI_LEN);
125 result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
126 WDRTAS_SP_SPI, __pa(rtas_data_buf),
127 WDRTAS_SP_SPI_LEN);
128
129 memcpy(value, rtas_data_buf, WDRTAS_SP_SPI_LEN);
130 spin_unlock(&rtas_data_buf_lock);
131
132 if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
133 pr_warn("could not get sp_spi watchdog timeout (%li). Continuing\n",
134 result);
135 return fallback_value;
136 }
137
138
139 return ((int)value[2]) * 60;
140}
141
142
143
144
145
146
147
148static void wdrtas_timer_start(void)
149{
150 wdrtas_set_interval(wdrtas_interval);
151}
152
153
154
155
156
157
158
159static void wdrtas_timer_stop(void)
160{
161 wdrtas_set_interval(0);
162}
163
164
165
166
167
168
169
170
171static void wdrtas_timer_keepalive(void)
172{
173 long result;
174
175 do {
176 result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
177 RTAS_EVENT_SCAN_ALL_EVENTS, 0,
178 (void *)__pa(wdrtas_logbuffer),
179 WDRTAS_LOGBUFFER_LEN);
180 if (result < 0)
181 pr_err("event-scan failed: %li\n", result);
182 if (result == 0)
183 print_hex_dump(KERN_INFO, "dumping event, data: ",
184 DUMP_PREFIX_OFFSET, 16, 1,
185 wdrtas_logbuffer, WDRTAS_LOGBUFFER_LEN, false);
186 } while (result == 0);
187}
188
189
190
191
192
193
194
195
196
197static int wdrtas_get_temperature(void)
198{
199 int result;
200 int temperature = 0;
201
202 result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
203
204 if (result < 0)
205 pr_warn("reading the thermal sensor failed: %i\n", result);
206 else
207 temperature = ((temperature * 9) / 5) + 32;
208
209 return temperature;
210}
211
212
213
214
215
216
217
218static int wdrtas_get_status(void)
219{
220 return 0;
221}
222
223
224
225
226
227
228
229static int wdrtas_get_boot_status(void)
230{
231 return 0;
232}
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249static ssize_t wdrtas_write(struct file *file, const char __user *buf,
250 size_t len, loff_t *ppos)
251{
252 int i;
253 char c;
254
255 if (!len)
256 goto out;
257
258 if (!wdrtas_nowayout) {
259 wdrtas_expect_close = 0;
260
261 for (i = 0; i < len; i++) {
262 if (get_user(c, buf + i))
263 return -EFAULT;
264
265 if (c == 'V')
266 wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
267 }
268 }
269
270 wdrtas_timer_keepalive();
271
272out:
273 return len;
274}
275
276
277
278
279
280
281
282
283
284
285
286
287static long wdrtas_ioctl(struct file *file, unsigned int cmd,
288 unsigned long arg)
289{
290 int __user *argp = (void __user *)arg;
291 int i;
292 static const struct watchdog_info wdinfo = {
293 .options = WDRTAS_SUPPORTED_MASK,
294 .firmware_version = 0,
295 .identity = "wdrtas",
296 };
297
298 switch (cmd) {
299 case WDIOC_GETSUPPORT:
300 if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
301 return -EFAULT;
302 return 0;
303
304 case WDIOC_GETSTATUS:
305 i = wdrtas_get_status();
306 return put_user(i, argp);
307
308 case WDIOC_GETBOOTSTATUS:
309 i = wdrtas_get_boot_status();
310 return put_user(i, argp);
311
312 case WDIOC_GETTEMP:
313 if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
314 return -EOPNOTSUPP;
315
316 i = wdrtas_get_temperature();
317 return put_user(i, argp);
318
319 case WDIOC_SETOPTIONS:
320 if (get_user(i, argp))
321 return -EFAULT;
322 if (i & WDIOS_DISABLECARD)
323 wdrtas_timer_stop();
324 if (i & WDIOS_ENABLECARD) {
325 wdrtas_timer_keepalive();
326 wdrtas_timer_start();
327 }
328
329
330
331 return 0;
332
333 case WDIOC_KEEPALIVE:
334 wdrtas_timer_keepalive();
335 return 0;
336
337 case WDIOC_SETTIMEOUT:
338 if (get_user(i, argp))
339 return -EFAULT;
340
341 if (wdrtas_set_interval(i))
342 return -EINVAL;
343
344 wdrtas_timer_keepalive();
345
346 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
347 wdrtas_interval = i;
348 else
349 wdrtas_interval = wdrtas_get_interval(i);
350
351
352 case WDIOC_GETTIMEOUT:
353 return put_user(wdrtas_interval, argp);
354
355 default:
356 return -ENOTTY;
357 }
358}
359
360
361
362
363
364
365
366
367
368
369
370static int wdrtas_open(struct inode *inode, struct file *file)
371{
372
373 if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
374 atomic_dec(&wdrtas_miscdev_open);
375 return -EBUSY;
376 }
377
378 wdrtas_timer_start();
379 wdrtas_timer_keepalive();
380
381 return nonseekable_open(inode, file);
382}
383
384
385
386
387
388
389
390
391
392
393static int wdrtas_close(struct inode *inode, struct file *file)
394{
395
396 if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
397 wdrtas_timer_stop();
398 else {
399 pr_warn("got unexpected close. Watchdog not stopped.\n");
400 wdrtas_timer_keepalive();
401 }
402
403 wdrtas_expect_close = 0;
404 atomic_dec(&wdrtas_miscdev_open);
405 return 0;
406}
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
422 size_t count, loff_t *ppos)
423{
424 int temperature = 0;
425
426 temperature = wdrtas_get_temperature();
427 if (temperature < 0)
428 return temperature;
429
430 if (copy_to_user(buf, &temperature, 1))
431 return -EFAULT;
432
433 return 1;
434}
435
436
437
438
439
440
441
442
443
444
445static int wdrtas_temp_open(struct inode *inode, struct file *file)
446{
447 return nonseekable_open(inode, file);
448}
449
450
451
452
453
454
455
456
457
458
459static int wdrtas_temp_close(struct inode *inode, struct file *file)
460{
461 return 0;
462}
463
464
465
466
467
468
469
470
471
472
473
474static int wdrtas_reboot(struct notifier_block *this,
475 unsigned long code, void *ptr)
476{
477 if (code == SYS_DOWN || code == SYS_HALT)
478 wdrtas_timer_stop();
479
480 return NOTIFY_DONE;
481}
482
483
484
485static const struct file_operations wdrtas_fops = {
486 .owner = THIS_MODULE,
487 .llseek = no_llseek,
488 .write = wdrtas_write,
489 .unlocked_ioctl = wdrtas_ioctl,
490 .open = wdrtas_open,
491 .release = wdrtas_close,
492};
493
494static struct miscdevice wdrtas_miscdev = {
495 .minor = WATCHDOG_MINOR,
496 .name = "watchdog",
497 .fops = &wdrtas_fops,
498};
499
500static const struct file_operations wdrtas_temp_fops = {
501 .owner = THIS_MODULE,
502 .llseek = no_llseek,
503 .read = wdrtas_temp_read,
504 .open = wdrtas_temp_open,
505 .release = wdrtas_temp_close,
506};
507
508static struct miscdevice wdrtas_tempdev = {
509 .minor = TEMP_MINOR,
510 .name = "temperature",
511 .fops = &wdrtas_temp_fops,
512};
513
514static struct notifier_block wdrtas_notifier = {
515 .notifier_call = wdrtas_reboot,
516};
517
518
519
520
521
522
523
524
525
526
527static int wdrtas_get_tokens(void)
528{
529 wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
530 if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
531 pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
532 }
533
534 wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
535 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
536 pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
537 WDRTAS_DEFAULT_INTERVAL);
538 }
539
540 wdrtas_token_set_indicator = rtas_token("set-indicator");
541 if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
542 pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
543 return -EIO;
544 }
545
546 wdrtas_token_event_scan = rtas_token("event-scan");
547 if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
548 pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
549 return -EIO;
550 }
551
552 return 0;
553}
554
555
556
557
558
559
560
561static void wdrtas_unregister_devs(void)
562{
563 misc_deregister(&wdrtas_miscdev);
564 if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
565 misc_deregister(&wdrtas_tempdev);
566}
567
568
569
570
571
572
573
574
575
576static int wdrtas_register_devs(void)
577{
578 int result;
579
580 result = misc_register(&wdrtas_miscdev);
581 if (result) {
582 pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
583 return result;
584 }
585
586 if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
587 result = misc_register(&wdrtas_tempdev);
588 if (result) {
589 pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
590 wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
591 }
592 }
593
594 return 0;
595}
596
597
598
599
600
601
602
603
604static int __init wdrtas_init(void)
605{
606 if (wdrtas_get_tokens())
607 return -ENODEV;
608
609 if (wdrtas_register_devs())
610 return -ENODEV;
611
612 if (register_reboot_notifier(&wdrtas_notifier)) {
613 pr_err("could not register reboot notifier. Terminating watchdog code.\n");
614 wdrtas_unregister_devs();
615 return -ENODEV;
616 }
617
618 if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
619 wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
620 else
621 wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
622
623 return 0;
624}
625
626
627
628
629
630
631static void __exit wdrtas_exit(void)
632{
633 if (!wdrtas_nowayout)
634 wdrtas_timer_stop();
635
636 wdrtas_unregister_devs();
637
638 unregister_reboot_notifier(&wdrtas_notifier);
639}
640
641module_init(wdrtas_init);
642module_exit(wdrtas_exit);
643