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

Add sun4v_wdt watchdog driver

This driver adds sparc hypervisor watchdog support. The default
timeout is 60 seconds and the range is between 1 and
31536000 seconds. Both watchdog-resolution and
watchdog-max-timeout MD properties settings are supported.

Signed-off-by: Wim Coekaerts <wim.coekaerts@oracle.com>
Reviewed-by: Julian Calaby <julian.calaby@gmail.com>
Reviewed-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

wim.coekaerts@oracle.com and committed by
David S. Miller
ca0bb079 1a40b953

+210 -1
+4
Documentation/watchdog/watchdog-parameters.txt
··· 400 400 nowayout: Watchdog cannot be stopped once started 401 401 (default=kernel config parameter) 402 402 ------------------------------------------------- 403 + sun4v_wdt: 404 + timeout_ms: Watchdog timeout in milliseconds 1..180000, default=60000) 405 + nowayout: Watchdog cannot be stopped once started 406 + -------------------------------------------------
+2 -1
arch/sparc/kernel/hvcalls.S
··· 338 338 mov %o1, %o4 339 339 mov HV_FAST_MACH_SET_WATCHDOG, %o5 340 340 ta HV_FAST_TRAP 341 + brnz,a,pn %o4, 0f 341 342 stx %o1, [%o4] 342 - retl 343 + 0: retl 343 344 nop 344 345 ENDPROC(sun4v_mach_set_watchdog) 345 346
+1
arch/sparc/kernel/sparc_ksyms_64.c
··· 37 37 EXPORT_SYMBOL(sun4v_niagara_setperf); 38 38 EXPORT_SYMBOL(sun4v_niagara2_getperf); 39 39 EXPORT_SYMBOL(sun4v_niagara2_setperf); 40 + EXPORT_SYMBOL(sun4v_mach_set_watchdog); 40 41 41 42 /* from hweight.S */ 42 43 EXPORT_SYMBOL(__arch_hweight8);
+11
drivers/watchdog/Kconfig
··· 1565 1565 machines. The watchdog timeout period is normally one minute but 1566 1566 can be changed with a boot-time parameter. 1567 1567 1568 + config WATCHDOG_SUN4V 1569 + tristate "Sun4v Watchdog support" 1570 + select WATCHDOG_CORE 1571 + depends on SPARC64 1572 + help 1573 + Say Y here to support the hypervisor watchdog capability embedded 1574 + in the SPARC sun4v architecture. 1575 + 1576 + To compile this driver as a module, choose M here. The module will 1577 + be called sun4v_wdt. 1578 + 1568 1579 # XTENSA Architecture 1569 1580 1570 1581 # Xen Architecture
+1
drivers/watchdog/Makefile
··· 179 179 180 180 obj-$(CONFIG_WATCHDOG_RIO) += riowd.o 181 181 obj-$(CONFIG_WATCHDOG_CP1XXX) += cpwd.o 182 + obj-$(CONFIG_WATCHDOG_SUN4V) += sun4v_wdt.o 182 183 183 184 # XTENSA Architecture 184 185
+191
drivers/watchdog/sun4v_wdt.c
··· 1 + /* 2 + * sun4v watchdog timer 3 + * (c) Copyright 2016 Oracle Corporation 4 + * 5 + * Implement a simple watchdog driver using the built-in sun4v hypervisor 6 + * watchdog support. If time expires, the hypervisor stops or bounces 7 + * the guest domain. 8 + * 9 + * This program is free software; you can redistribute it and/or 10 + * modify it under the terms of the GNU General Public License 11 + * as published by the Free Software Foundation; either version 12 + * 2 of the License, or (at your option) any later version. 13 + */ 14 + 15 + #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 16 + 17 + #include <linux/errno.h> 18 + #include <linux/init.h> 19 + #include <linux/kernel.h> 20 + #include <linux/module.h> 21 + #include <linux/moduleparam.h> 22 + #include <linux/watchdog.h> 23 + #include <asm/hypervisor.h> 24 + #include <asm/mdesc.h> 25 + 26 + #define WDT_TIMEOUT 60 27 + #define WDT_MAX_TIMEOUT 31536000 28 + #define WDT_MIN_TIMEOUT 1 29 + #define WDT_DEFAULT_RESOLUTION_MS 1000 /* 1 second */ 30 + 31 + static unsigned int timeout; 32 + module_param(timeout, uint, 0); 33 + MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default=" 34 + __MODULE_STRING(WDT_TIMEOUT) ")"); 35 + 36 + static bool nowayout = WATCHDOG_NOWAYOUT; 37 + module_param(nowayout, bool, S_IRUGO); 38 + MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" 39 + __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 40 + 41 + static int sun4v_wdt_stop(struct watchdog_device *wdd) 42 + { 43 + sun4v_mach_set_watchdog(0, NULL); 44 + 45 + return 0; 46 + } 47 + 48 + static int sun4v_wdt_ping(struct watchdog_device *wdd) 49 + { 50 + int hverr; 51 + 52 + /* 53 + * HV watchdog timer will round up the timeout 54 + * passed in to the nearest multiple of the 55 + * watchdog resolution in milliseconds. 56 + */ 57 + hverr = sun4v_mach_set_watchdog(wdd->timeout * 1000, NULL); 58 + if (hverr == HV_EINVAL) 59 + return -EINVAL; 60 + 61 + return 0; 62 + } 63 + 64 + static int sun4v_wdt_set_timeout(struct watchdog_device *wdd, 65 + unsigned int timeout) 66 + { 67 + wdd->timeout = timeout; 68 + 69 + return 0; 70 + } 71 + 72 + static const struct watchdog_info sun4v_wdt_ident = { 73 + .options = WDIOF_SETTIMEOUT | 74 + WDIOF_MAGICCLOSE | 75 + WDIOF_KEEPALIVEPING, 76 + .identity = "sun4v hypervisor watchdog", 77 + .firmware_version = 0, 78 + }; 79 + 80 + static struct watchdog_ops sun4v_wdt_ops = { 81 + .owner = THIS_MODULE, 82 + .start = sun4v_wdt_ping, 83 + .stop = sun4v_wdt_stop, 84 + .ping = sun4v_wdt_ping, 85 + .set_timeout = sun4v_wdt_set_timeout, 86 + }; 87 + 88 + static struct watchdog_device wdd = { 89 + .info = &sun4v_wdt_ident, 90 + .ops = &sun4v_wdt_ops, 91 + .min_timeout = WDT_MIN_TIMEOUT, 92 + .max_timeout = WDT_MAX_TIMEOUT, 93 + .timeout = WDT_TIMEOUT, 94 + }; 95 + 96 + static int __init sun4v_wdt_init(void) 97 + { 98 + struct mdesc_handle *handle; 99 + u64 node; 100 + const u64 *value; 101 + int err = 0; 102 + unsigned long major = 1, minor = 1; 103 + 104 + /* 105 + * There are 2 properties that can be set from the control 106 + * domain for the watchdog. 107 + * watchdog-resolution 108 + * watchdog-max-timeout 109 + * 110 + * We can expect a handle to be returned otherwise something 111 + * serious is wrong. Correct to return -ENODEV here. 112 + */ 113 + 114 + handle = mdesc_grab(); 115 + if (!handle) 116 + return -ENODEV; 117 + 118 + node = mdesc_node_by_name(handle, MDESC_NODE_NULL, "platform"); 119 + err = -ENODEV; 120 + if (node == MDESC_NODE_NULL) 121 + goto out_release; 122 + 123 + /* 124 + * This is a safe way to validate if we are on the right 125 + * platform. 126 + */ 127 + if (sun4v_hvapi_register(HV_GRP_CORE, major, &minor)) 128 + goto out_hv_unreg; 129 + 130 + /* Allow value of watchdog-resolution up to 1s (default) */ 131 + value = mdesc_get_property(handle, node, "watchdog-resolution", NULL); 132 + err = -EINVAL; 133 + if (value) { 134 + if (*value == 0 || 135 + *value > WDT_DEFAULT_RESOLUTION_MS) 136 + goto out_hv_unreg; 137 + } 138 + 139 + value = mdesc_get_property(handle, node, "watchdog-max-timeout", NULL); 140 + if (value) { 141 + /* 142 + * If the property value (in ms) is smaller than 143 + * min_timeout, return -EINVAL. 144 + */ 145 + if (*value < wdd.min_timeout * 1000) 146 + goto out_hv_unreg; 147 + 148 + /* 149 + * If the property value is smaller than 150 + * default max_timeout then set watchdog max_timeout to 151 + * the value of the property in seconds. 152 + */ 153 + if (*value < wdd.max_timeout * 1000) 154 + wdd.max_timeout = *value / 1000; 155 + } 156 + 157 + watchdog_init_timeout(&wdd, timeout, NULL); 158 + 159 + watchdog_set_nowayout(&wdd, nowayout); 160 + 161 + err = watchdog_register_device(&wdd); 162 + if (err) 163 + goto out_hv_unreg; 164 + 165 + pr_info("initialized (timeout=%ds, nowayout=%d)\n", 166 + wdd.timeout, nowayout); 167 + 168 + mdesc_release(handle); 169 + 170 + return 0; 171 + 172 + out_hv_unreg: 173 + sun4v_hvapi_unregister(HV_GRP_CORE); 174 + 175 + out_release: 176 + mdesc_release(handle); 177 + return err; 178 + } 179 + 180 + static void __exit sun4v_wdt_exit(void) 181 + { 182 + sun4v_hvapi_unregister(HV_GRP_CORE); 183 + watchdog_unregister_device(&wdd); 184 + } 185 + 186 + module_init(sun4v_wdt_init); 187 + module_exit(sun4v_wdt_exit); 188 + 189 + MODULE_AUTHOR("Wim Coekaerts <wim.coekaerts@oracle.com>"); 190 + MODULE_DESCRIPTION("sun4v watchdog driver"); 191 + MODULE_LICENSE("GPL");