Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/watchdog: use watchdog API

Converted the vmwatchdog driver to use the kernel's watchdog API.

Signed-off-by: Philipp Hachtmann <phacht@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Philipp Hachtmann and committed by
Martin Schwidefsky
f7a94db4 f2485f5d

+294 -341
+1
arch/s390/configs/default_defconfig
··· 456 456 CONFIG_WATCHDOG=y 457 457 CONFIG_WATCHDOG_NOWAYOUT=y 458 458 CONFIG_SOFT_WATCHDOG=m 459 + CONFIG_DIAG288_WATCHDOG=m 459 460 # CONFIG_HID is not set 460 461 # CONFIG_USB_SUPPORT is not set 461 462 CONFIG_INFINIBAND=m
+1
arch/s390/configs/gcov_defconfig
··· 453 453 CONFIG_WATCHDOG=y 454 454 CONFIG_WATCHDOG_NOWAYOUT=y 455 455 CONFIG_SOFT_WATCHDOG=m 456 + CONFIG_DIAG288_WATCHDOG=m 456 457 # CONFIG_HID is not set 457 458 # CONFIG_USB_SUPPORT is not set 458 459 CONFIG_INFINIBAND=m
+1
arch/s390/configs/performance_defconfig
··· 451 451 CONFIG_WATCHDOG=y 452 452 CONFIG_WATCHDOG_NOWAYOUT=y 453 453 CONFIG_SOFT_WATCHDOG=m 454 + CONFIG_DIAG288_WATCHDOG=m 454 455 # CONFIG_HID is not set 455 456 # CONFIG_USB_SUPPORT is not set 456 457 CONFIG_INFINIBAND=m
-1
drivers/s390/char/Makefile
··· 19 19 obj-$(CONFIG_SCLP_CPI) += sclp_cpi.o 20 20 obj-$(CONFIG_SCLP_ASYNC) += sclp_async.o 21 21 22 - obj-$(CONFIG_ZVM_WATCHDOG) += vmwatchdog.o 23 22 obj-$(CONFIG_VMLOGRDR) += vmlogrdr.o 24 23 obj-$(CONFIG_VMCP) += vmcp.o 25 24
-338
drivers/s390/char/vmwatchdog.c
··· 1 - /* 2 - * Watchdog implementation based on z/VM Watchdog Timer API 3 - * 4 - * Copyright IBM Corp. 2004, 2009 5 - * 6 - * The user space watchdog daemon can use this driver as 7 - * /dev/vmwatchdog to have z/VM execute the specified CP 8 - * command when the timeout expires. The default command is 9 - * "IPL", which which cause an immediate reboot. 10 - */ 11 - #define KMSG_COMPONENT "vmwatchdog" 12 - #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 13 - 14 - #include <linux/init.h> 15 - #include <linux/fs.h> 16 - #include <linux/kernel.h> 17 - #include <linux/miscdevice.h> 18 - #include <linux/module.h> 19 - #include <linux/moduleparam.h> 20 - #include <linux/slab.h> 21 - #include <linux/suspend.h> 22 - #include <linux/watchdog.h> 23 - 24 - #include <asm/ebcdic.h> 25 - #include <asm/io.h> 26 - #include <asm/uaccess.h> 27 - 28 - #define MAX_CMDLEN 240 29 - #define MIN_INTERVAL 15 30 - static char vmwdt_cmd[MAX_CMDLEN] = "IPL"; 31 - static bool vmwdt_conceal; 32 - 33 - static bool vmwdt_nowayout = WATCHDOG_NOWAYOUT; 34 - 35 - MODULE_LICENSE("GPL"); 36 - MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 37 - MODULE_DESCRIPTION("z/VM Watchdog Timer"); 38 - module_param_string(cmd, vmwdt_cmd, MAX_CMDLEN, 0644); 39 - MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers"); 40 - module_param_named(conceal, vmwdt_conceal, bool, 0644); 41 - MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog " 42 - " is active"); 43 - module_param_named(nowayout, vmwdt_nowayout, bool, 0); 44 - MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started" 45 - " (default=CONFIG_WATCHDOG_NOWAYOUT)"); 46 - MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 47 - 48 - static unsigned int vmwdt_interval = 60; 49 - static unsigned long vmwdt_is_open; 50 - static int vmwdt_expect_close; 51 - 52 - static DEFINE_MUTEX(vmwdt_mutex); 53 - 54 - #define VMWDT_OPEN 0 /* devnode is open or suspend in progress */ 55 - #define VMWDT_RUNNING 1 /* The watchdog is armed */ 56 - 57 - enum vmwdt_func { 58 - /* function codes */ 59 - wdt_init = 0, 60 - wdt_change = 1, 61 - wdt_cancel = 2, 62 - /* flags */ 63 - wdt_conceal = 0x80000000, 64 - }; 65 - 66 - static int __diag288(enum vmwdt_func func, unsigned int timeout, 67 - char *cmd, size_t len) 68 - { 69 - register unsigned long __func asm("2") = func; 70 - register unsigned long __timeout asm("3") = timeout; 71 - register unsigned long __cmdp asm("4") = virt_to_phys(cmd); 72 - register unsigned long __cmdl asm("5") = len; 73 - int err; 74 - 75 - err = -EINVAL; 76 - asm volatile( 77 - " diag %1,%3,0x288\n" 78 - "0: la %0,0\n" 79 - "1:\n" 80 - EX_TABLE(0b,1b) 81 - : "+d" (err) : "d"(__func), "d"(__timeout), 82 - "d"(__cmdp), "d"(__cmdl) : "1", "cc"); 83 - return err; 84 - } 85 - 86 - static int vmwdt_keepalive(void) 87 - { 88 - /* we allocate new memory every time to avoid having 89 - * to track the state. static allocation is not an 90 - * option since that might not be contiguous in real 91 - * storage in case of a modular build */ 92 - static char *ebc_cmd; 93 - size_t len; 94 - int ret; 95 - unsigned int func; 96 - 97 - ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); 98 - if (!ebc_cmd) 99 - return -ENOMEM; 100 - 101 - len = strlcpy(ebc_cmd, vmwdt_cmd, MAX_CMDLEN); 102 - ASCEBC(ebc_cmd, MAX_CMDLEN); 103 - EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); 104 - 105 - func = vmwdt_conceal ? (wdt_init | wdt_conceal) : wdt_init; 106 - set_bit(VMWDT_RUNNING, &vmwdt_is_open); 107 - ret = __diag288(func, vmwdt_interval, ebc_cmd, len); 108 - WARN_ON(ret != 0); 109 - kfree(ebc_cmd); 110 - return ret; 111 - } 112 - 113 - static int vmwdt_disable(void) 114 - { 115 - char cmd[] = {'\0'}; 116 - int ret = __diag288(wdt_cancel, 0, cmd, 0); 117 - WARN_ON(ret != 0); 118 - clear_bit(VMWDT_RUNNING, &vmwdt_is_open); 119 - return ret; 120 - } 121 - 122 - static int __init vmwdt_probe(void) 123 - { 124 - /* there is no real way to see if the watchdog is supported, 125 - * so we try initializing it with a NOP command ("BEGIN") 126 - * that won't cause any harm even if the following disable 127 - * fails for some reason */ 128 - char ebc_begin[] = { 129 - 194, 197, 199, 201, 213 130 - }; 131 - if (__diag288(wdt_init, 15, ebc_begin, sizeof(ebc_begin)) != 0) 132 - return -EINVAL; 133 - return vmwdt_disable(); 134 - } 135 - 136 - static int vmwdt_open(struct inode *i, struct file *f) 137 - { 138 - int ret; 139 - if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) 140 - return -EBUSY; 141 - ret = vmwdt_keepalive(); 142 - if (ret) 143 - clear_bit(VMWDT_OPEN, &vmwdt_is_open); 144 - return ret ? ret : nonseekable_open(i, f); 145 - } 146 - 147 - static int vmwdt_close(struct inode *i, struct file *f) 148 - { 149 - if (vmwdt_expect_close == 42) 150 - vmwdt_disable(); 151 - vmwdt_expect_close = 0; 152 - clear_bit(VMWDT_OPEN, &vmwdt_is_open); 153 - return 0; 154 - } 155 - 156 - static struct watchdog_info vmwdt_info = { 157 - .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 158 - .firmware_version = 0, 159 - .identity = "z/VM Watchdog Timer", 160 - }; 161 - 162 - static int __vmwdt_ioctl(unsigned int cmd, unsigned long arg) 163 - { 164 - switch (cmd) { 165 - case WDIOC_GETSUPPORT: 166 - if (copy_to_user((void __user *)arg, &vmwdt_info, 167 - sizeof(vmwdt_info))) 168 - return -EFAULT; 169 - return 0; 170 - case WDIOC_GETSTATUS: 171 - case WDIOC_GETBOOTSTATUS: 172 - return put_user(0, (int __user *)arg); 173 - case WDIOC_GETTEMP: 174 - return -EINVAL; 175 - case WDIOC_SETOPTIONS: 176 - { 177 - int options, ret; 178 - if (get_user(options, (int __user *)arg)) 179 - return -EFAULT; 180 - ret = -EINVAL; 181 - if (options & WDIOS_DISABLECARD) { 182 - ret = vmwdt_disable(); 183 - if (ret) 184 - return ret; 185 - } 186 - if (options & WDIOS_ENABLECARD) { 187 - ret = vmwdt_keepalive(); 188 - } 189 - return ret; 190 - } 191 - case WDIOC_GETTIMEOUT: 192 - return put_user(vmwdt_interval, (int __user *)arg); 193 - case WDIOC_SETTIMEOUT: 194 - { 195 - int interval; 196 - if (get_user(interval, (int __user *)arg)) 197 - return -EFAULT; 198 - if (interval < MIN_INTERVAL) 199 - return -EINVAL; 200 - vmwdt_interval = interval; 201 - } 202 - return vmwdt_keepalive(); 203 - case WDIOC_KEEPALIVE: 204 - return vmwdt_keepalive(); 205 - } 206 - return -EINVAL; 207 - } 208 - 209 - static long vmwdt_ioctl(struct file *f, unsigned int cmd, unsigned long arg) 210 - { 211 - int rc; 212 - 213 - mutex_lock(&vmwdt_mutex); 214 - rc = __vmwdt_ioctl(cmd, arg); 215 - mutex_unlock(&vmwdt_mutex); 216 - return (long) rc; 217 - } 218 - 219 - static ssize_t vmwdt_write(struct file *f, const char __user *buf, 220 - size_t count, loff_t *ppos) 221 - { 222 - if(count) { 223 - if (!vmwdt_nowayout) { 224 - size_t i; 225 - 226 - /* note: just in case someone wrote the magic character 227 - * five months ago... */ 228 - vmwdt_expect_close = 0; 229 - 230 - for (i = 0; i != count; i++) { 231 - char c; 232 - if (get_user(c, buf+i)) 233 - return -EFAULT; 234 - if (c == 'V') 235 - vmwdt_expect_close = 42; 236 - } 237 - } 238 - /* someone wrote to us, we should restart timer */ 239 - vmwdt_keepalive(); 240 - } 241 - return count; 242 - } 243 - 244 - static int vmwdt_resume(void) 245 - { 246 - clear_bit(VMWDT_OPEN, &vmwdt_is_open); 247 - return NOTIFY_DONE; 248 - } 249 - 250 - /* 251 - * It makes no sense to go into suspend while the watchdog is running. 252 - * Depending on the memory size, the watchdog might trigger, while we 253 - * are still saving the memory. 254 - * We reuse the open flag to ensure that suspend and watchdog open are 255 - * exclusive operations 256 - */ 257 - static int vmwdt_suspend(void) 258 - { 259 - if (test_and_set_bit(VMWDT_OPEN, &vmwdt_is_open)) { 260 - pr_err("The system cannot be suspended while the watchdog" 261 - " is in use\n"); 262 - return notifier_from_errno(-EBUSY); 263 - } 264 - if (test_bit(VMWDT_RUNNING, &vmwdt_is_open)) { 265 - clear_bit(VMWDT_OPEN, &vmwdt_is_open); 266 - pr_err("The system cannot be suspended while the watchdog" 267 - " is running\n"); 268 - return notifier_from_errno(-EBUSY); 269 - } 270 - return NOTIFY_DONE; 271 - } 272 - 273 - /* 274 - * This function is called for suspend and resume. 275 - */ 276 - static int vmwdt_power_event(struct notifier_block *this, unsigned long event, 277 - void *ptr) 278 - { 279 - switch (event) { 280 - case PM_POST_HIBERNATION: 281 - case PM_POST_SUSPEND: 282 - return vmwdt_resume(); 283 - case PM_HIBERNATION_PREPARE: 284 - case PM_SUSPEND_PREPARE: 285 - return vmwdt_suspend(); 286 - default: 287 - return NOTIFY_DONE; 288 - } 289 - } 290 - 291 - static struct notifier_block vmwdt_power_notifier = { 292 - .notifier_call = vmwdt_power_event, 293 - }; 294 - 295 - static const struct file_operations vmwdt_fops = { 296 - .open = &vmwdt_open, 297 - .release = &vmwdt_close, 298 - .unlocked_ioctl = &vmwdt_ioctl, 299 - .write = &vmwdt_write, 300 - .owner = THIS_MODULE, 301 - .llseek = noop_llseek, 302 - }; 303 - 304 - static struct miscdevice vmwdt_dev = { 305 - .minor = WATCHDOG_MINOR, 306 - .name = "watchdog", 307 - .fops = &vmwdt_fops, 308 - }; 309 - 310 - static int __init vmwdt_init(void) 311 - { 312 - int ret; 313 - 314 - ret = vmwdt_probe(); 315 - if (ret) 316 - return ret; 317 - ret = register_pm_notifier(&vmwdt_power_notifier); 318 - if (ret) 319 - return ret; 320 - /* 321 - * misc_register() has to be the last action in module_init(), because 322 - * file operations will be available right after this. 323 - */ 324 - ret = misc_register(&vmwdt_dev); 325 - if (ret) { 326 - unregister_pm_notifier(&vmwdt_power_notifier); 327 - return ret; 328 - } 329 - return 0; 330 - } 331 - module_init(vmwdt_init); 332 - 333 - static void __exit vmwdt_exit(void) 334 - { 335 - unregister_pm_notifier(&vmwdt_power_notifier); 336 - misc_deregister(&vmwdt_dev); 337 - } 338 - module_exit(vmwdt_exit);
+3 -2
drivers/watchdog/Kconfig
··· 1295 1295 1296 1296 # S390 Architecture 1297 1297 1298 - config ZVM_WATCHDOG 1299 - tristate "z/VM Watchdog Timer" 1298 + config DIAG288_WATCHDOG 1299 + tristate "System z diag288 Watchdog" 1300 1300 depends on S390 1301 + select WATCHDOG_CORE 1301 1302 help 1302 1303 IBM s/390 and zSeries machines running under z/VM 5.1 or later 1303 1304 provide a virtual watchdog timer to their guest that cause a
+1
drivers/watchdog/Makefile
··· 154 154 obj-$(CONFIG_WATCHDOG_RTAS) += wdrtas.o 155 155 156 156 # S390 Architecture 157 + obj-$(CONFIG_DIAG288_WATCHDOG) += diag288_wdt.o 157 158 158 159 # SUPERH (sh + sh64) Architecture 159 160 obj-$(CONFIG_SH_WDT) += shwdt.o
+287
drivers/watchdog/diag288_wdt.c
··· 1 + /* 2 + * Watchdog driver for z/VM using the diag 288 interface. 3 + * 4 + * Under z/VM, expiration of the watchdog will send a "system restart" command 5 + * to CP. 6 + * 7 + * The command can be altered using the module parameter "cmd". 8 + * 9 + * Copyright IBM Corp. 2004, 2013 10 + * Author(s): Arnd Bergmann (arndb@de.ibm.com) 11 + * Philipp Hachtmann (phacht@de.ibm.com) 12 + * 13 + */ 14 + 15 + #define KMSG_COMPONENT "diag288_wdt" 16 + #define pr_fmt(fmt) KMSG_COMPONENT ": " fmt 17 + 18 + #include <linux/init.h> 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/moduleparam.h> 22 + #include <linux/slab.h> 23 + #include <linux/miscdevice.h> 24 + #include <linux/watchdog.h> 25 + #include <linux/suspend.h> 26 + #include <asm/ebcdic.h> 27 + #include <linux/io.h> 28 + #include <linux/uaccess.h> 29 + 30 + #define MAX_CMDLEN 240 31 + #define DEFAULT_CMD "SYSTEM RESTART" 32 + 33 + #define MIN_INTERVAL 15 /* Minimal time supported by diag88 */ 34 + #define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */ 35 + 36 + #define WDT_DEFAULT_TIMEOUT 30 37 + 38 + /* Function codes - init, change, cancel */ 39 + #define WDT_FUNC_INIT 0 40 + #define WDT_FUNC_CHANGE 1 41 + #define WDT_FUNC_CANCEL 2 42 + #define WDT_FUNC_CONCEAL 0x80000000 43 + 44 + static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD; 45 + static bool conceal_on; 46 + static bool nowayout_info = WATCHDOG_NOWAYOUT; 47 + 48 + MODULE_LICENSE("GPL"); 49 + MODULE_AUTHOR("Arnd Bergmann <arndb@de.ibm.com>"); 50 + MODULE_AUTHOR("Philipp Hachtmann <phacht@de.ibm.com>"); 51 + 52 + MODULE_DESCRIPTION("System z diag288 Watchdog Timer"); 53 + 54 + module_param_string(cmd, wdt_cmd, MAX_CMDLEN, 0644); 55 + MODULE_PARM_DESC(cmd, "CP command that is run when the watchdog triggers (z/VM only)"); 56 + 57 + module_param_named(conceal, conceal_on, bool, 0644); 58 + MODULE_PARM_DESC(conceal, "Enable the CONCEAL CP option while the watchdog is active (z/VM only)"); 59 + 60 + module_param_named(nowayout, nowayout_info, bool, 0444); 61 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default = CONFIG_WATCHDOG_NOWAYOUT)"); 62 + 63 + MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR); 64 + MODULE_ALIAS("vmwatchdog"); 65 + 66 + static int __diag288(unsigned int func, unsigned int timeout, 67 + unsigned long action, unsigned int len) 68 + { 69 + register unsigned long __func asm("2") = func; 70 + register unsigned long __timeout asm("3") = timeout; 71 + register unsigned long __action asm("4") = action; 72 + register unsigned long __len asm("5") = len; 73 + int err; 74 + 75 + err = -EINVAL; 76 + asm volatile( 77 + " diag %1, %3, 0x288\n" 78 + "0: la %0, 0\n" 79 + "1:\n" 80 + EX_TABLE(0b, 1b) 81 + : "+d" (err) : "d"(__func), "d"(__timeout), 82 + "d"(__action), "d"(__len) : "1", "cc"); 83 + return err; 84 + } 85 + 86 + static int __diag288_vm(unsigned int func, unsigned int timeout, 87 + char *cmd, size_t len) 88 + { 89 + return __diag288(func, timeout, virt_to_phys(cmd), len); 90 + } 91 + 92 + static int wdt_start(struct watchdog_device *dev) 93 + { 94 + char *ebc_cmd; 95 + size_t len; 96 + int ret; 97 + unsigned int func; 98 + 99 + ret = -ENODEV; 100 + 101 + if (MACHINE_IS_VM) { 102 + ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); 103 + if (!ebc_cmd) 104 + return -ENOMEM; 105 + len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN); 106 + ASCEBC(ebc_cmd, MAX_CMDLEN); 107 + EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); 108 + 109 + func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL) 110 + : WDT_FUNC_INIT; 111 + ret = __diag288_vm(func, dev->timeout, ebc_cmd, len); 112 + WARN_ON(ret != 0); 113 + kfree(ebc_cmd); 114 + } 115 + 116 + if (ret) { 117 + pr_err("The watchdog cannot be activated\n"); 118 + return ret; 119 + } 120 + pr_info("The watchdog was activated\n"); 121 + return 0; 122 + } 123 + 124 + static int wdt_stop(struct watchdog_device *dev) 125 + { 126 + int ret; 127 + 128 + ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0); 129 + pr_info("The watchdog was deactivated\n"); 130 + return ret; 131 + } 132 + 133 + static int wdt_ping(struct watchdog_device *dev) 134 + { 135 + char *ebc_cmd; 136 + size_t len; 137 + int ret; 138 + unsigned int func; 139 + 140 + ret = -ENODEV; 141 + 142 + if (MACHINE_IS_VM) { 143 + ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL); 144 + if (!ebc_cmd) 145 + return -ENOMEM; 146 + len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN); 147 + ASCEBC(ebc_cmd, MAX_CMDLEN); 148 + EBC_TOUPPER(ebc_cmd, MAX_CMDLEN); 149 + 150 + /* 151 + * It seems to be ok to z/VM to use the init function to 152 + * retrigger the watchdog. 153 + */ 154 + func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL) 155 + : WDT_FUNC_INIT; 156 + 157 + ret = __diag288_vm(func, dev->timeout, ebc_cmd, len); 158 + WARN_ON(ret != 0); 159 + kfree(ebc_cmd); 160 + } 161 + 162 + if (ret) 163 + pr_err("The watchdog timer cannot be started or reset\n"); 164 + return ret; 165 + } 166 + 167 + static int wdt_set_timeout(struct watchdog_device * dev, unsigned int new_to) 168 + { 169 + dev->timeout = new_to; 170 + return wdt_ping(dev); 171 + } 172 + 173 + static struct watchdog_ops wdt_ops = { 174 + .owner = THIS_MODULE, 175 + .start = wdt_start, 176 + .stop = wdt_stop, 177 + .ping = wdt_ping, 178 + .set_timeout = wdt_set_timeout, 179 + }; 180 + 181 + static struct watchdog_info wdt_info = { 182 + .options = WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, 183 + .firmware_version = 0, 184 + .identity = "z Watchdog", 185 + }; 186 + 187 + static struct watchdog_device wdt_dev = { 188 + .parent = NULL, 189 + .info = &wdt_info, 190 + .ops = &wdt_ops, 191 + .bootstatus = 0, 192 + .timeout = WDT_DEFAULT_TIMEOUT, 193 + .min_timeout = MIN_INTERVAL, 194 + .max_timeout = MAX_INTERVAL, 195 + }; 196 + 197 + /* 198 + * It makes no sense to go into suspend while the watchdog is running. 199 + * Depending on the memory size, the watchdog might trigger, while we 200 + * are still saving the memory. 201 + * We reuse the open flag to ensure that suspend and watchdog open are 202 + * exclusive operations 203 + */ 204 + static int wdt_suspend(void) 205 + { 206 + if (test_and_set_bit(WDOG_DEV_OPEN, &wdt_dev.status)) { 207 + pr_err("Linux cannot be suspended while the watchdog is in use\n"); 208 + return notifier_from_errno(-EBUSY); 209 + } 210 + if (test_bit(WDOG_ACTIVE, &wdt_dev.status)) { 211 + clear_bit(WDOG_DEV_OPEN, &wdt_dev.status); 212 + pr_err("Linux cannot be suspended while the watchdog is in use\n"); 213 + return notifier_from_errno(-EBUSY); 214 + } 215 + return NOTIFY_DONE; 216 + } 217 + 218 + static int wdt_resume(void) 219 + { 220 + clear_bit(WDOG_DEV_OPEN, &wdt_dev.status); 221 + return NOTIFY_DONE; 222 + } 223 + 224 + static int wdt_power_event(struct notifier_block *this, unsigned long event, 225 + void *ptr) 226 + { 227 + switch (event) { 228 + case PM_POST_HIBERNATION: 229 + case PM_POST_SUSPEND: 230 + return wdt_resume(); 231 + case PM_HIBERNATION_PREPARE: 232 + case PM_SUSPEND_PREPARE: 233 + return wdt_suspend(); 234 + default: 235 + return NOTIFY_DONE; 236 + } 237 + } 238 + 239 + static struct notifier_block wdt_power_notifier = { 240 + .notifier_call = wdt_power_event, 241 + }; 242 + 243 + static int __init diag288_init(void) 244 + { 245 + int ret; 246 + char ebc_begin[] = { 247 + 194, 197, 199, 201, 213 248 + }; 249 + 250 + watchdog_set_nowayout(&wdt_dev, nowayout_info); 251 + 252 + if (MACHINE_IS_VM) { 253 + pr_info("The watchdog device driver detected a z/VM environment\n"); 254 + if (__diag288_vm(WDT_FUNC_INIT, 15, 255 + ebc_begin, sizeof(ebc_begin)) != 0) { 256 + pr_err("The watchdog cannot be initialized\n"); 257 + return -EINVAL; 258 + } 259 + } else { 260 + pr_err("Linux runs in an environment that does not support the diag288 watchdog\n"); 261 + return -ENODEV; 262 + } 263 + 264 + if (__diag288_vm(WDT_FUNC_CANCEL, 0, NULL, 0)) { 265 + pr_err("The watchdog cannot be deactivated\n"); 266 + return -EINVAL; 267 + } 268 + 269 + ret = register_pm_notifier(&wdt_power_notifier); 270 + if (ret) 271 + return ret; 272 + 273 + ret = watchdog_register_device(&wdt_dev); 274 + if (ret) 275 + unregister_pm_notifier(&wdt_power_notifier); 276 + 277 + return ret; 278 + } 279 + 280 + static void __exit diag288_exit(void) 281 + { 282 + watchdog_unregister_device(&wdt_dev); 283 + unregister_pm_notifier(&wdt_power_notifier); 284 + } 285 + 286 + module_init(diag288_init); 287 + module_exit(diag288_exit);