Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
wdrtas.c
Go to the documentation of this file.
1 /*
2  * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
3  * RTAS calls are available
4  */
5 
6 /*
7  * RTAS watchdog driver
8  *
9  * (C) Copyright IBM Corp. 2005
10  * device driver to exploit watchdog RTAS functions
11  *
12  * Authors : Utz Bacher <[email protected]>
13  *
14  * This program is free software; you can redistribute it and/or modify
15  * it under the terms of the GNU General Public License as published by
16  * the Free Software Foundation; either version 2, or (at your option)
17  * any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software
26  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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 
48 MODULE_AUTHOR("Utz Bacher <[email protected]>");
49 MODULE_DESCRIPTION("RTAS watchdog driver");
50 MODULE_LICENSE("GPL");
53 
54 static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
55 static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
56 static char wdrtas_expect_close;
57 
58 static int wdrtas_interval;
59 
60 #define WDRTAS_THERMAL_SENSOR 3
61 static int wdrtas_token_get_sensor_state;
62 #define WDRTAS_SURVEILLANCE_IND 9000
63 static int wdrtas_token_set_indicator;
64 #define WDRTAS_SP_SPI 28
65 static int wdrtas_token_get_sp;
66 static int wdrtas_token_event_scan;
67 
68 #define WDRTAS_DEFAULT_INTERVAL 300
69 
70 #define WDRTAS_LOGBUFFER_LEN 128
71 static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
72 
73 
74 /*** watchdog access functions */
75 
87 static int wdrtas_set_interval(int interval)
88 {
89  long result;
90  static int print_msg = 10;
91 
92  /* rtas uses minutes */
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 
118 static 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),
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  /* rtas uses minutes */
139  return ((int)value[2]) * 60;
140 }
141 
148 static void wdrtas_timer_start(void)
149 {
150  wdrtas_set_interval(wdrtas_interval);
151 }
152 
159 static void wdrtas_timer_stop(void)
160 {
161  wdrtas_set_interval(0);
162 }
163 
170 static void wdrtas_log_scanned_event(void)
171 {
172  int i;
173 
174  for (i = 0; i < WDRTAS_LOGBUFFER_LEN; i += 16)
175  pr_info("dumping event (line %i/%i), data = "
176  "%02x %02x %02x %02x %02x %02x %02x %02x "
177  "%02x %02x %02x %02x %02x %02x %02x %02x\n",
178  (i / 16) + 1, (WDRTAS_LOGBUFFER_LEN / 16),
179  wdrtas_logbuffer[i + 0], wdrtas_logbuffer[i + 1],
180  wdrtas_logbuffer[i + 2], wdrtas_logbuffer[i + 3],
181  wdrtas_logbuffer[i + 4], wdrtas_logbuffer[i + 5],
182  wdrtas_logbuffer[i + 6], wdrtas_logbuffer[i + 7],
183  wdrtas_logbuffer[i + 8], wdrtas_logbuffer[i + 9],
184  wdrtas_logbuffer[i + 10], wdrtas_logbuffer[i + 11],
185  wdrtas_logbuffer[i + 12], wdrtas_logbuffer[i + 13],
186  wdrtas_logbuffer[i + 14], wdrtas_logbuffer[i + 15]);
187 }
188 
196 static void wdrtas_timer_keepalive(void)
197 {
198  long result;
199 
200  do {
201  result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
202  RTAS_EVENT_SCAN_ALL_EVENTS, 0,
203  (void *)__pa(wdrtas_logbuffer),
204  WDRTAS_LOGBUFFER_LEN);
205  if (result < 0)
206  pr_err("event-scan failed: %li\n", result);
207  if (result == 0)
208  wdrtas_log_scanned_event();
209  } while (result == 0);
210 }
211 
220 static int wdrtas_get_temperature(void)
221 {
222  int result;
223  int temperature = 0;
224 
225  result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
226 
227  if (result < 0)
228  pr_warn("reading the thermal sensor failed: %i\n", result);
229  else
230  temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
231 
232  return temperature;
233 }
234 
241 static int wdrtas_get_status(void)
242 {
243  return 0; /* TODO */
244 }
245 
252 static int wdrtas_get_boot_status(void)
253 {
254  return 0; /* TODO */
255 }
256 
257 /*** watchdog API and operations stuff */
258 
259 /* wdrtas_write - called when watchdog device is written to
260  * @file: file structure
261  * @buf: user buffer with data
262  * @len: amount to data written
263  * @ppos: position in file
264  *
265  * returns the number of successfully processed characters, which is always
266  * the number of bytes passed to this function
267  *
268  * wdrtas_write processes all the data given to it and looks for the magic
269  * character 'V'. This character allows the watchdog device to be closed
270  * properly.
271  */
272 static ssize_t wdrtas_write(struct file *file, const char __user *buf,
273  size_t len, loff_t *ppos)
274 {
275  int i;
276  char c;
277 
278  if (!len)
279  goto out;
280 
281  if (!wdrtas_nowayout) {
282  wdrtas_expect_close = 0;
283  /* look for 'V' */
284  for (i = 0; i < len; i++) {
285  if (get_user(c, buf + i))
286  return -EFAULT;
287  /* allow to close device */
288  if (c == 'V')
289  wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
290  }
291  }
292 
293  wdrtas_timer_keepalive();
294 
295 out:
296  return len;
297 }
298 
310 static long wdrtas_ioctl(struct file *file, unsigned int cmd,
311  unsigned long arg)
312 {
313  int __user *argp = (void __user *)arg;
314  int i;
315  static const struct watchdog_info wdinfo = {
317  .firmware_version = 0,
318  .identity = "wdrtas",
319  };
320 
321  switch (cmd) {
322  case WDIOC_GETSUPPORT:
323  if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
324  return -EFAULT;
325  return 0;
326 
327  case WDIOC_GETSTATUS:
328  i = wdrtas_get_status();
329  return put_user(i, argp);
330 
331  case WDIOC_GETBOOTSTATUS:
332  i = wdrtas_get_boot_status();
333  return put_user(i, argp);
334 
335  case WDIOC_GETTEMP:
336  if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
337  return -EOPNOTSUPP;
338 
339  i = wdrtas_get_temperature();
340  return put_user(i, argp);
341 
342  case WDIOC_SETOPTIONS:
343  if (get_user(i, argp))
344  return -EFAULT;
345  if (i & WDIOS_DISABLECARD)
346  wdrtas_timer_stop();
347  if (i & WDIOS_ENABLECARD) {
348  wdrtas_timer_keepalive();
349  wdrtas_timer_start();
350  }
351  /* not implemented. Done by H8
352  if (i & WDIOS_TEMPPANIC) {
353  } */
354  return 0;
355 
356  case WDIOC_KEEPALIVE:
357  wdrtas_timer_keepalive();
358  return 0;
359 
360  case WDIOC_SETTIMEOUT:
361  if (get_user(i, argp))
362  return -EFAULT;
363 
364  if (wdrtas_set_interval(i))
365  return -EINVAL;
366 
367  wdrtas_timer_keepalive();
368 
369  if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
370  wdrtas_interval = i;
371  else
372  wdrtas_interval = wdrtas_get_interval(i);
373  /* fallthrough */
374 
375  case WDIOC_GETTIMEOUT:
376  return put_user(wdrtas_interval, argp);
377 
378  default:
379  return -ENOTTY;
380  }
381 }
382 
393 static int wdrtas_open(struct inode *inode, struct file *file)
394 {
395  /* only open once */
396  if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
397  atomic_dec(&wdrtas_miscdev_open);
398  return -EBUSY;
399  }
400 
401  wdrtas_timer_start();
402  wdrtas_timer_keepalive();
403 
404  return nonseekable_open(inode, file);
405 }
406 
416 static int wdrtas_close(struct inode *inode, struct file *file)
417 {
418  /* only stop watchdog, if this was announced using 'V' before */
419  if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
420  wdrtas_timer_stop();
421  else {
422  pr_warn("got unexpected close. Watchdog not stopped.\n");
423  wdrtas_timer_keepalive();
424  }
425 
426  wdrtas_expect_close = 0;
427  atomic_dec(&wdrtas_miscdev_open);
428  return 0;
429 }
430 
444 static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
445  size_t count, loff_t *ppos)
446 {
447  int temperature = 0;
448 
449  temperature = wdrtas_get_temperature();
450  if (temperature < 0)
451  return temperature;
452 
453  if (copy_to_user(buf, &temperature, 1))
454  return -EFAULT;
455 
456  return 1;
457 }
458 
468 static int wdrtas_temp_open(struct inode *inode, struct file *file)
469 {
470  return nonseekable_open(inode, file);
471 }
472 
482 static int wdrtas_temp_close(struct inode *inode, struct file *file)
483 {
484  return 0;
485 }
486 
497 static int wdrtas_reboot(struct notifier_block *this,
498  unsigned long code, void *ptr)
499 {
500  if (code == SYS_DOWN || code == SYS_HALT)
501  wdrtas_timer_stop();
502 
503  return NOTIFY_DONE;
504 }
505 
506 /*** initialization stuff */
507 
508 static const struct file_operations wdrtas_fops = {
509  .owner = THIS_MODULE,
510  .llseek = no_llseek,
511  .write = wdrtas_write,
512  .unlocked_ioctl = wdrtas_ioctl,
513  .open = wdrtas_open,
514  .release = wdrtas_close,
515 };
516 
517 static struct miscdevice wdrtas_miscdev = {
519  .name = "watchdog",
520  .fops = &wdrtas_fops,
521 };
522 
523 static const struct file_operations wdrtas_temp_fops = {
524  .owner = THIS_MODULE,
525  .llseek = no_llseek,
526  .read = wdrtas_temp_read,
527  .open = wdrtas_temp_open,
528  .release = wdrtas_temp_close,
529 };
530 
531 static struct miscdevice wdrtas_tempdev = {
532  .minor = TEMP_MINOR,
533  .name = "temperature",
534  .fops = &wdrtas_temp_fops,
535 };
536 
537 static struct notifier_block wdrtas_notifier = {
538  .notifier_call = wdrtas_reboot,
539 };
540 
550 static int wdrtas_get_tokens(void)
551 {
552  wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
553  if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
554  pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
555  }
556 
557  wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
558  if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
559  pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
561  }
562 
563  wdrtas_token_set_indicator = rtas_token("set-indicator");
564  if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
565  pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
566  return -EIO;
567  }
568 
569  wdrtas_token_event_scan = rtas_token("event-scan");
570  if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
571  pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
572  return -EIO;
573  }
574 
575  return 0;
576 }
577 
584 static void wdrtas_unregister_devs(void)
585 {
586  misc_deregister(&wdrtas_miscdev);
587  if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
588  misc_deregister(&wdrtas_tempdev);
589 }
590 
599 static int wdrtas_register_devs(void)
600 {
601  int result;
602 
603  result = misc_register(&wdrtas_miscdev);
604  if (result) {
605  pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
606  return result;
607  }
608 
609  if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
610  result = misc_register(&wdrtas_tempdev);
611  if (result) {
612  pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
613  wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
614  }
615  }
616 
617  return 0;
618 }
619 
627 static int __init wdrtas_init(void)
628 {
629  if (wdrtas_get_tokens())
630  return -ENODEV;
631 
632  if (wdrtas_register_devs())
633  return -ENODEV;
634 
635  if (register_reboot_notifier(&wdrtas_notifier)) {
636  pr_err("could not register reboot notifier. Terminating watchdog code.\n");
637  wdrtas_unregister_devs();
638  return -ENODEV;
639  }
640 
641  if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
642  wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
643  else
644  wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
645 
646  return 0;
647 }
648 
654 static void __exit wdrtas_exit(void)
655 {
656  if (!wdrtas_nowayout)
657  wdrtas_timer_stop();
658 
659  wdrtas_unregister_devs();
660 
661  unregister_reboot_notifier(&wdrtas_notifier);
662 }
663 
664 module_init(wdrtas_init);
665 module_exit(wdrtas_exit);