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