Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * FIXME: add wdrtas_get_status and wdrtas_get_boot_status as soon as
0004  * RTAS calls are available
0005  */
0006 
0007 /*
0008  * RTAS watchdog driver
0009  *
0010  * (C) Copyright IBM Corp. 2005
0011  * device driver to exploit watchdog RTAS functions
0012  *
0013  * Authors : Utz Bacher <utz.bacher@de.ibm.com>
0014  */
0015 
0016 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0017 
0018 #include <linux/fs.h>
0019 #include <linux/init.h>
0020 #include <linux/kernel.h>
0021 #include <linux/miscdevice.h>
0022 #include <linux/module.h>
0023 #include <linux/notifier.h>
0024 #include <linux/reboot.h>
0025 #include <linux/types.h>
0026 #include <linux/watchdog.h>
0027 #include <linux/uaccess.h>
0028 
0029 #include <asm/rtas.h>
0030 
0031 #define WDRTAS_MAGIC_CHAR       42
0032 #define WDRTAS_SUPPORTED_MASK       (WDIOF_SETTIMEOUT | \
0033                      WDIOF_MAGICCLOSE)
0034 
0035 MODULE_AUTHOR("Utz Bacher <utz.bacher@de.ibm.com>");
0036 MODULE_DESCRIPTION("RTAS watchdog driver");
0037 MODULE_LICENSE("GPL");
0038 
0039 static bool wdrtas_nowayout = WATCHDOG_NOWAYOUT;
0040 static atomic_t wdrtas_miscdev_open = ATOMIC_INIT(0);
0041 static char wdrtas_expect_close;
0042 
0043 static int wdrtas_interval;
0044 
0045 #define WDRTAS_THERMAL_SENSOR       3
0046 static int wdrtas_token_get_sensor_state;
0047 #define WDRTAS_SURVEILLANCE_IND     9000
0048 static int wdrtas_token_set_indicator;
0049 #define WDRTAS_SP_SPI           28
0050 static int wdrtas_token_get_sp;
0051 static int wdrtas_token_event_scan;
0052 
0053 #define WDRTAS_DEFAULT_INTERVAL     300
0054 
0055 #define WDRTAS_LOGBUFFER_LEN        128
0056 static char wdrtas_logbuffer[WDRTAS_LOGBUFFER_LEN];
0057 
0058 
0059 /*** watchdog access functions */
0060 
0061 /**
0062  * wdrtas_set_interval - sets the watchdog interval
0063  * @interval: new interval
0064  *
0065  * returns 0 on success, <0 on failures
0066  *
0067  * wdrtas_set_interval sets the watchdog keepalive interval by calling the
0068  * RTAS function set-indicator (surveillance). The unit of interval is
0069  * seconds.
0070  */
0071 
0072 static int wdrtas_set_interval(int interval)
0073 {
0074     long result;
0075     static int print_msg = 10;
0076 
0077     /* rtas uses minutes */
0078     interval = (interval + 59) / 60;
0079 
0080     result = rtas_call(wdrtas_token_set_indicator, 3, 1, NULL,
0081                WDRTAS_SURVEILLANCE_IND, 0, interval);
0082     if (result < 0 && print_msg) {
0083         pr_err("setting the watchdog to %i timeout failed: %li\n",
0084                interval, result);
0085         print_msg--;
0086     }
0087 
0088     return result;
0089 }
0090 
0091 #define WDRTAS_SP_SPI_LEN 4
0092 
0093 /**
0094  * wdrtas_get_interval - returns the current watchdog interval
0095  * @fallback_value: value (in seconds) to use, if the RTAS call fails
0096  *
0097  * returns the interval
0098  *
0099  * wdrtas_get_interval returns the current watchdog keepalive interval
0100  * as reported by the RTAS function ibm,get-system-parameter. The unit
0101  * of the return value is seconds.
0102  */
0103 static int wdrtas_get_interval(int fallback_value)
0104 {
0105     long result;
0106     char value[WDRTAS_SP_SPI_LEN];
0107 
0108     spin_lock(&rtas_data_buf_lock);
0109     memset(rtas_data_buf, 0, WDRTAS_SP_SPI_LEN);
0110     result = rtas_call(wdrtas_token_get_sp, 3, 1, NULL,
0111                WDRTAS_SP_SPI, __pa(rtas_data_buf),
0112                WDRTAS_SP_SPI_LEN);
0113 
0114     memcpy(value, rtas_data_buf, WDRTAS_SP_SPI_LEN);
0115     spin_unlock(&rtas_data_buf_lock);
0116 
0117     if (value[0] != 0 || value[1] != 2 || value[3] != 0 || result < 0) {
0118         pr_warn("could not get sp_spi watchdog timeout (%li). Continuing\n",
0119             result);
0120         return fallback_value;
0121     }
0122 
0123     /* rtas uses minutes */
0124     return ((int)value[2]) * 60;
0125 }
0126 
0127 /**
0128  * wdrtas_timer_start - starts watchdog
0129  *
0130  * wdrtas_timer_start starts the watchdog by calling the RTAS function
0131  * set-interval (surveillance)
0132  */
0133 static void wdrtas_timer_start(void)
0134 {
0135     wdrtas_set_interval(wdrtas_interval);
0136 }
0137 
0138 /**
0139  * wdrtas_timer_stop - stops watchdog
0140  *
0141  * wdrtas_timer_stop stops the watchdog timer by calling the RTAS function
0142  * set-interval (surveillance)
0143  */
0144 static void wdrtas_timer_stop(void)
0145 {
0146     wdrtas_set_interval(0);
0147 }
0148 
0149 /**
0150  * wdrtas_timer_keepalive - resets watchdog timer to keep system alive
0151  *
0152  * wdrtas_timer_keepalive restarts the watchdog timer by calling the
0153  * RTAS function event-scan and repeats these calls as long as there are
0154  * events available. All events will be dumped.
0155  */
0156 static void wdrtas_timer_keepalive(void)
0157 {
0158     long result;
0159 
0160     do {
0161         result = rtas_call(wdrtas_token_event_scan, 4, 1, NULL,
0162                    RTAS_EVENT_SCAN_ALL_EVENTS, 0,
0163                    (void *)__pa(wdrtas_logbuffer),
0164                    WDRTAS_LOGBUFFER_LEN);
0165         if (result < 0)
0166             pr_err("event-scan failed: %li\n", result);
0167         if (result == 0)
0168             print_hex_dump(KERN_INFO, "dumping event, data: ",
0169                 DUMP_PREFIX_OFFSET, 16, 1,
0170                 wdrtas_logbuffer, WDRTAS_LOGBUFFER_LEN, false);
0171     } while (result == 0);
0172 }
0173 
0174 /**
0175  * wdrtas_get_temperature - returns current temperature
0176  *
0177  * returns temperature or <0 on failures
0178  *
0179  * wdrtas_get_temperature returns the current temperature in Fahrenheit. It
0180  * uses the RTAS call get-sensor-state, token 3 to do so
0181  */
0182 static int wdrtas_get_temperature(void)
0183 {
0184     int result;
0185     int temperature = 0;
0186 
0187     result = rtas_get_sensor(WDRTAS_THERMAL_SENSOR, 0, &temperature);
0188 
0189     if (result < 0)
0190         pr_warn("reading the thermal sensor failed: %i\n", result);
0191     else
0192         temperature = ((temperature * 9) / 5) + 32; /* fahrenheit */
0193 
0194     return temperature;
0195 }
0196 
0197 /**
0198  * wdrtas_get_status - returns the status of the watchdog
0199  *
0200  * returns a bitmask of defines WDIOF_... as defined in
0201  * include/linux/watchdog.h
0202  */
0203 static int wdrtas_get_status(void)
0204 {
0205     return 0; /* TODO */
0206 }
0207 
0208 /**
0209  * wdrtas_get_boot_status - returns the reason for the last boot
0210  *
0211  * returns a bitmask of defines WDIOF_... as defined in
0212  * include/linux/watchdog.h, indicating why the watchdog rebooted the system
0213  */
0214 static int wdrtas_get_boot_status(void)
0215 {
0216     return 0; /* TODO */
0217 }
0218 
0219 /*** watchdog API and operations stuff */
0220 
0221 /* wdrtas_write - called when watchdog device is written to
0222  * @file: file structure
0223  * @buf: user buffer with data
0224  * @len: amount to data written
0225  * @ppos: position in file
0226  *
0227  * returns the number of successfully processed characters, which is always
0228  * the number of bytes passed to this function
0229  *
0230  * wdrtas_write processes all the data given to it and looks for the magic
0231  * character 'V'. This character allows the watchdog device to be closed
0232  * properly.
0233  */
0234 static ssize_t wdrtas_write(struct file *file, const char __user *buf,
0235          size_t len, loff_t *ppos)
0236 {
0237     int i;
0238     char c;
0239 
0240     if (!len)
0241         goto out;
0242 
0243     if (!wdrtas_nowayout) {
0244         wdrtas_expect_close = 0;
0245         /* look for 'V' */
0246         for (i = 0; i < len; i++) {
0247             if (get_user(c, buf + i))
0248                 return -EFAULT;
0249             /* allow to close device */
0250             if (c == 'V')
0251                 wdrtas_expect_close = WDRTAS_MAGIC_CHAR;
0252         }
0253     }
0254 
0255     wdrtas_timer_keepalive();
0256 
0257 out:
0258     return len;
0259 }
0260 
0261 /**
0262  * wdrtas_ioctl - ioctl function for the watchdog device
0263  * @file: file structure
0264  * @cmd: command for ioctl
0265  * @arg: argument pointer
0266  *
0267  * returns 0 on success, <0 on failure
0268  *
0269  * wdrtas_ioctl implements the watchdog API ioctls
0270  */
0271 
0272 static long wdrtas_ioctl(struct file *file, unsigned int cmd,
0273                             unsigned long arg)
0274 {
0275     int __user *argp = (void __user *)arg;
0276     int i;
0277     static const struct watchdog_info wdinfo = {
0278         .options = WDRTAS_SUPPORTED_MASK,
0279         .firmware_version = 0,
0280         .identity = "wdrtas",
0281     };
0282 
0283     switch (cmd) {
0284     case WDIOC_GETSUPPORT:
0285         if (copy_to_user(argp, &wdinfo, sizeof(wdinfo)))
0286             return -EFAULT;
0287         return 0;
0288 
0289     case WDIOC_GETSTATUS:
0290         i = wdrtas_get_status();
0291         return put_user(i, argp);
0292 
0293     case WDIOC_GETBOOTSTATUS:
0294         i = wdrtas_get_boot_status();
0295         return put_user(i, argp);
0296 
0297     case WDIOC_GETTEMP:
0298         if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE)
0299             return -EOPNOTSUPP;
0300 
0301         i = wdrtas_get_temperature();
0302         return put_user(i, argp);
0303 
0304     case WDIOC_SETOPTIONS:
0305         if (get_user(i, argp))
0306             return -EFAULT;
0307         if (i & WDIOS_DISABLECARD)
0308             wdrtas_timer_stop();
0309         if (i & WDIOS_ENABLECARD) {
0310             wdrtas_timer_keepalive();
0311             wdrtas_timer_start();
0312         }
0313         /* not implemented. Done by H8
0314         if (i & WDIOS_TEMPPANIC) {
0315         } */
0316         return 0;
0317 
0318     case WDIOC_KEEPALIVE:
0319         wdrtas_timer_keepalive();
0320         return 0;
0321 
0322     case WDIOC_SETTIMEOUT:
0323         if (get_user(i, argp))
0324             return -EFAULT;
0325 
0326         if (wdrtas_set_interval(i))
0327             return -EINVAL;
0328 
0329         wdrtas_timer_keepalive();
0330 
0331         if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
0332             wdrtas_interval = i;
0333         else
0334             wdrtas_interval = wdrtas_get_interval(i);
0335         fallthrough;
0336 
0337     case WDIOC_GETTIMEOUT:
0338         return put_user(wdrtas_interval, argp);
0339 
0340     default:
0341         return -ENOTTY;
0342     }
0343 }
0344 
0345 /**
0346  * wdrtas_open - open function of watchdog device
0347  * @inode: inode structure
0348  * @file: file structure
0349  *
0350  * returns 0 on success, -EBUSY if the file has been opened already, <0 on
0351  * other failures
0352  *
0353  * function called when watchdog device is opened
0354  */
0355 static int wdrtas_open(struct inode *inode, struct file *file)
0356 {
0357     /* only open once */
0358     if (atomic_inc_return(&wdrtas_miscdev_open) > 1) {
0359         atomic_dec(&wdrtas_miscdev_open);
0360         return -EBUSY;
0361     }
0362 
0363     wdrtas_timer_start();
0364     wdrtas_timer_keepalive();
0365 
0366     return stream_open(inode, file);
0367 }
0368 
0369 /**
0370  * wdrtas_close - close function of watchdog device
0371  * @inode: inode structure
0372  * @file: file structure
0373  *
0374  * returns 0 on success
0375  *
0376  * close function. Always succeeds
0377  */
0378 static int wdrtas_close(struct inode *inode, struct file *file)
0379 {
0380     /* only stop watchdog, if this was announced using 'V' before */
0381     if (wdrtas_expect_close == WDRTAS_MAGIC_CHAR)
0382         wdrtas_timer_stop();
0383     else {
0384         pr_warn("got unexpected close. Watchdog not stopped.\n");
0385         wdrtas_timer_keepalive();
0386     }
0387 
0388     wdrtas_expect_close = 0;
0389     atomic_dec(&wdrtas_miscdev_open);
0390     return 0;
0391 }
0392 
0393 /**
0394  * wdrtas_temp_read - gives back the temperature in fahrenheit
0395  * @file: file structure
0396  * @buf: user buffer
0397  * @count: number of bytes to be read
0398  * @ppos: position in file
0399  *
0400  * returns always 1 or -EFAULT in case of user space copy failures, <0 on
0401  * other failures
0402  *
0403  * wdrtas_temp_read gives the temperature to the users by copying this
0404  * value as one byte into the user space buffer. The unit is Fahrenheit...
0405  */
0406 static ssize_t wdrtas_temp_read(struct file *file, char __user *buf,
0407          size_t count, loff_t *ppos)
0408 {
0409     int temperature = 0;
0410 
0411     temperature = wdrtas_get_temperature();
0412     if (temperature < 0)
0413         return temperature;
0414 
0415     if (copy_to_user(buf, &temperature, 1))
0416         return -EFAULT;
0417 
0418     return 1;
0419 }
0420 
0421 /**
0422  * wdrtas_temp_open - open function of temperature device
0423  * @inode: inode structure
0424  * @file: file structure
0425  *
0426  * returns 0 on success, <0 on failure
0427  *
0428  * function called when temperature device is opened
0429  */
0430 static int wdrtas_temp_open(struct inode *inode, struct file *file)
0431 {
0432     return stream_open(inode, file);
0433 }
0434 
0435 /**
0436  * wdrtas_temp_close - close function of temperature device
0437  * @inode: inode structure
0438  * @file: file structure
0439  *
0440  * returns 0 on success
0441  *
0442  * close function. Always succeeds
0443  */
0444 static int wdrtas_temp_close(struct inode *inode, struct file *file)
0445 {
0446     return 0;
0447 }
0448 
0449 /**
0450  * wdrtas_reboot - reboot notifier function
0451  * @nb: notifier block structure
0452  * @code: reboot code
0453  * @ptr: unused
0454  *
0455  * returns NOTIFY_DONE
0456  *
0457  * wdrtas_reboot stops the watchdog in case of a reboot
0458  */
0459 static int wdrtas_reboot(struct notifier_block *this,
0460                     unsigned long code, void *ptr)
0461 {
0462     if (code == SYS_DOWN || code == SYS_HALT)
0463         wdrtas_timer_stop();
0464 
0465     return NOTIFY_DONE;
0466 }
0467 
0468 /*** initialization stuff */
0469 
0470 static const struct file_operations wdrtas_fops = {
0471     .owner      = THIS_MODULE,
0472     .llseek     = no_llseek,
0473     .write      = wdrtas_write,
0474     .unlocked_ioctl = wdrtas_ioctl,
0475     .compat_ioctl   = compat_ptr_ioctl,
0476     .open       = wdrtas_open,
0477     .release    = wdrtas_close,
0478 };
0479 
0480 static struct miscdevice wdrtas_miscdev = {
0481     .minor =    WATCHDOG_MINOR,
0482     .name =     "watchdog",
0483     .fops =     &wdrtas_fops,
0484 };
0485 
0486 static const struct file_operations wdrtas_temp_fops = {
0487     .owner      = THIS_MODULE,
0488     .llseek     = no_llseek,
0489     .read       = wdrtas_temp_read,
0490     .open       = wdrtas_temp_open,
0491     .release    = wdrtas_temp_close,
0492 };
0493 
0494 static struct miscdevice wdrtas_tempdev = {
0495     .minor =    TEMP_MINOR,
0496     .name =     "temperature",
0497     .fops =     &wdrtas_temp_fops,
0498 };
0499 
0500 static struct notifier_block wdrtas_notifier = {
0501     .notifier_call =    wdrtas_reboot,
0502 };
0503 
0504 /**
0505  * wdrtas_get_tokens - reads in RTAS tokens
0506  *
0507  * returns 0 on success, <0 on failure
0508  *
0509  * wdrtas_get_tokens reads in the tokens for the RTAS calls used in
0510  * this watchdog driver. It tolerates, if "get-sensor-state" and
0511  * "ibm,get-system-parameter" are not available.
0512  */
0513 static int wdrtas_get_tokens(void)
0514 {
0515     wdrtas_token_get_sensor_state = rtas_token("get-sensor-state");
0516     if (wdrtas_token_get_sensor_state == RTAS_UNKNOWN_SERVICE) {
0517         pr_warn("couldn't get token for get-sensor-state. Trying to continue without temperature support.\n");
0518     }
0519 
0520     wdrtas_token_get_sp = rtas_token("ibm,get-system-parameter");
0521     if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE) {
0522         pr_warn("couldn't get token for ibm,get-system-parameter. Trying to continue with a default timeout value of %i seconds.\n",
0523             WDRTAS_DEFAULT_INTERVAL);
0524     }
0525 
0526     wdrtas_token_set_indicator = rtas_token("set-indicator");
0527     if (wdrtas_token_set_indicator == RTAS_UNKNOWN_SERVICE) {
0528         pr_err("couldn't get token for set-indicator. Terminating watchdog code.\n");
0529         return -EIO;
0530     }
0531 
0532     wdrtas_token_event_scan = rtas_token("event-scan");
0533     if (wdrtas_token_event_scan == RTAS_UNKNOWN_SERVICE) {
0534         pr_err("couldn't get token for event-scan. Terminating watchdog code.\n");
0535         return -EIO;
0536     }
0537 
0538     return 0;
0539 }
0540 
0541 /**
0542  * wdrtas_unregister_devs - unregisters the misc dev handlers
0543  *
0544  * wdrtas_register_devs unregisters the watchdog and temperature watchdog
0545  * misc devs
0546  */
0547 static void wdrtas_unregister_devs(void)
0548 {
0549     misc_deregister(&wdrtas_miscdev);
0550     if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE)
0551         misc_deregister(&wdrtas_tempdev);
0552 }
0553 
0554 /**
0555  * wdrtas_register_devs - registers the misc dev handlers
0556  *
0557  * returns 0 on success, <0 on failure
0558  *
0559  * wdrtas_register_devs registers the watchdog and temperature watchdog
0560  * misc devs
0561  */
0562 static int wdrtas_register_devs(void)
0563 {
0564     int result;
0565 
0566     result = misc_register(&wdrtas_miscdev);
0567     if (result) {
0568         pr_err("couldn't register watchdog misc device. Terminating watchdog code.\n");
0569         return result;
0570     }
0571 
0572     if (wdrtas_token_get_sensor_state != RTAS_UNKNOWN_SERVICE) {
0573         result = misc_register(&wdrtas_tempdev);
0574         if (result) {
0575             pr_warn("couldn't register watchdog temperature misc device. Continuing without temperature support.\n");
0576             wdrtas_token_get_sensor_state = RTAS_UNKNOWN_SERVICE;
0577         }
0578     }
0579 
0580     return 0;
0581 }
0582 
0583 /**
0584  * wdrtas_init - init function of the watchdog driver
0585  *
0586  * returns 0 on success, <0 on failure
0587  *
0588  * registers the file handlers and the reboot notifier
0589  */
0590 static int __init wdrtas_init(void)
0591 {
0592     if (wdrtas_get_tokens())
0593         return -ENODEV;
0594 
0595     if (wdrtas_register_devs())
0596         return -ENODEV;
0597 
0598     if (register_reboot_notifier(&wdrtas_notifier)) {
0599         pr_err("could not register reboot notifier. Terminating watchdog code.\n");
0600         wdrtas_unregister_devs();
0601         return -ENODEV;
0602     }
0603 
0604     if (wdrtas_token_get_sp == RTAS_UNKNOWN_SERVICE)
0605         wdrtas_interval = WDRTAS_DEFAULT_INTERVAL;
0606     else
0607         wdrtas_interval = wdrtas_get_interval(WDRTAS_DEFAULT_INTERVAL);
0608 
0609     return 0;
0610 }
0611 
0612 /**
0613  * wdrtas_exit - exit function of the watchdog driver
0614  *
0615  * unregisters the file handlers and the reboot notifier
0616  */
0617 static void __exit wdrtas_exit(void)
0618 {
0619     if (!wdrtas_nowayout)
0620         wdrtas_timer_stop();
0621 
0622     wdrtas_unregister_devs();
0623 
0624     unregister_reboot_notifier(&wdrtas_notifier);
0625 }
0626 
0627 module_init(wdrtas_init);
0628 module_exit(wdrtas_exit);