1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Watchdog driver for z/VM and LPAR using the diag 288 interface. 4 * 5 * Under z/VM, expiration of the watchdog will send a "system restart" command 6 * to CP. 7 * 8 * The command can be altered using the module parameter "cmd". This is 9 * not recommended because it's only supported on z/VM but not whith LPAR. 10 * 11 * On LPAR, the watchdog will always trigger a system restart. the module 12 * paramter cmd is meaningless here. 13 * 14 * 15 * Copyright IBM Corp. 2004, 2013 16 * Author(s): Arnd Bergmann (arndb@de.ibm.com) 17 * Philipp Hachtmann (phacht@de.ibm.com) 18 * 19 */ 20 21 #define KMSG_COMPONENT "diag288_wdt" 22 #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 23 24 #include <linux/init.h> 25 #include <linux/kernel.h> 26 #include <linux/module.h> 27 #include <linux/moduleparam.h> 28 #include <linux/slab.h> 29 #include <linux/watchdog.h> 30 #include <asm/machine.h> 31 #include <asm/ebcdic.h> 32 #include <asm/diag288.h> 33 #include <asm/diag.h> 34 #include <linux/io.h> 35 36 #define MAX_CMDLEN 240 37 #define DEFAULT_CMD "SYSTEM RESTART" 38 39 static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD; 40 static bool conceal_on; 41 static bool nowayout_info = WATCHDOG_NOWAYOUT; 42 43 MODULE_LICENSE("GPL"); 44 MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 45 MODULE_AUTHOR("Philipp Hachtmann <phacht@de.ibm.com>"); 46 47 MODULE_DESCRIPTION("System z diag288 Watchdog Timer"); 48 49 module_param_string(cmd, wdt_cmd, MAX_CMDLEN, 0644); 50 MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers (z/VM only)"); 51 52 module_param_named(conceal, conceal_on, bool, 0644); 53 MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog is active (z/VM only)"); 54 55 module_param_named(nowayout, nowayout_info, bool, 0444); 56 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default = CONFIG_WATCHDOG_NOWAYOUT)"); 57 58 MODULE_ALIAS("vmwatchdog"); 59 60 static char *cmd_buf; 61 62 static int diag288(unsigned int func, unsigned int timeout, 63 unsigned long action, unsigned int len) 64 { 65 diag_stat_inc(DIAG_STAT_X288); 66 return __diag288(func, timeout, action, len); 67 } 68 69 static int diag288_str(unsigned int func, unsigned int timeout, char *cmd) 70 { 71 ssize_t len; 72 73 len = strscpy(cmd_buf, cmd, MAX_CMDLEN); 74 if (len < 0) 75 return len; 76 ASCEBC(cmd_buf, MAX_CMDLEN); 77 EBC_TOUPPER(cmd_buf, MAX_CMDLEN); 78 79 return diag288(func, timeout, virt_to_phys(cmd_buf), len); 80 } 81 82 static int wdt_start(struct watchdog_device *dev) 83 { 84 int ret; 85 unsigned int func; 86 87 if (machine_is_vm()) { 88 func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL) 89 : WDT_FUNC_INIT; 90 ret = diag288_str(func, dev->timeout, wdt_cmd); 91 WARN_ON(ret != 0); 92 } else { 93 ret = diag288(WDT_FUNC_INIT, dev->timeout, LPARWDT_RESTART, 0); 94 } 95 96 if (ret) { 97 pr_err("The watchdog cannot be activated\n"); 98 return ret; 99 } 100 return 0; 101 } 102 103 static int wdt_stop(struct watchdog_device *dev) 104 { 105 return diag288(WDT_FUNC_CANCEL, 0, 0, 0); 106 } 107 108 static int wdt_ping(struct watchdog_device *dev) 109 { 110 int ret; 111 unsigned int func; 112 113 if (machine_is_vm()) { 114 /* 115 * It seems to be ok to z/VM to use the init function to 116 * retrigger the watchdog. On LPAR WDT_FUNC_CHANGE must 117 * be used when the watchdog is running. 118 */ 119 func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL) 120 : WDT_FUNC_INIT; 121 122 ret = diag288_str(func, dev->timeout, wdt_cmd); 123 WARN_ON(ret != 0); 124 } else { 125 ret = diag288(WDT_FUNC_CHANGE, dev->timeout, 0, 0); 126 } 127 128 if (ret) 129 pr_err("The watchdog timer cannot be started or reset\n"); 130 return ret; 131 } 132 133 static int wdt_set_timeout(struct watchdog_device * dev, unsigned int new_to) 134 { 135 dev->timeout = new_to; 136 return wdt_ping(dev); 137 } 138 139 static const struct watchdog_ops wdt_ops = { 140 .owner = THIS_MODULE, 141 .start = wdt_start, 142 .stop = wdt_stop, 143 .ping = wdt_ping, 144 .set_timeout = wdt_set_timeout, 145 }; 146 147 static const struct watchdog_info wdt_info = { 148 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 149 .firmware_version = 0, 150 .identity = "z Watchdog", 151 }; 152 153 static struct watchdog_device wdt_dev = { 154 .parent = NULL, 155 .info = &wdt_info, 156 .ops = &wdt_ops, 157 .bootstatus = 0, 158 .timeout = WDT_DEFAULT_TIMEOUT, 159 .min_timeout = MIN_INTERVAL, 160 .max_timeout = MAX_INTERVAL, 161 }; 162 163 static int __init diag288_init(void) 164 { 165 watchdog_set_nowayout(&wdt_dev, nowayout_info); 166 167 if (machine_is_vm()) { 168 cmd_buf = kmalloc(MAX_CMDLEN, GFP_KERNEL); 169 if (!cmd_buf) { 170 pr_err("The watchdog cannot be initialized\n"); 171 return -ENOMEM; 172 } 173 } 174 175 return watchdog_register_device(&wdt_dev); 176 } 177 178 static void __exit diag288_exit(void) 179 { 180 watchdog_unregister_device(&wdt_dev); 181 kfree(cmd_buf); 182 } 183 184 module_cpu_feature_match(S390_CPU_FEATURE_D288, diag288_init); 185 module_exit(diag288_exit); 186