root/drivers/watchdog/sun4v_wdt.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sun4v_wdt_stop
  2. sun4v_wdt_ping
  3. sun4v_wdt_set_timeout
  4. sun4v_wdt_init
  5. sun4v_wdt_exit

   1 // SPDX-License-Identifier: GPL-2.0-or-later
   2 /*
   3  *      sun4v watchdog timer
   4  *      (c) Copyright 2016 Oracle Corporation
   5  *
   6  *      Implement a simple watchdog driver using the built-in sun4v hypervisor
   7  *      watchdog support. If time expires, the hypervisor stops or bounces
   8  *      the guest domain.
   9  */
  10 
  11 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  12 
  13 #include <linux/errno.h>
  14 #include <linux/init.h>
  15 #include <linux/kernel.h>
  16 #include <linux/module.h>
  17 #include <linux/moduleparam.h>
  18 #include <linux/watchdog.h>
  19 #include <asm/hypervisor.h>
  20 #include <asm/mdesc.h>
  21 
  22 #define WDT_TIMEOUT                     60
  23 #define WDT_MAX_TIMEOUT                 31536000
  24 #define WDT_MIN_TIMEOUT                 1
  25 #define WDT_DEFAULT_RESOLUTION_MS       1000    /* 1 second */
  26 
  27 static unsigned int timeout;
  28 module_param(timeout, uint, 0);
  29 MODULE_PARM_DESC(timeout, "Watchdog timeout in seconds (default="
  30         __MODULE_STRING(WDT_TIMEOUT) ")");
  31 
  32 static bool nowayout = WATCHDOG_NOWAYOUT;
  33 module_param(nowayout, bool, S_IRUGO);
  34 MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default="
  35         __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
  36 
  37 static int sun4v_wdt_stop(struct watchdog_device *wdd)
  38 {
  39         sun4v_mach_set_watchdog(0, NULL);
  40 
  41         return 0;
  42 }
  43 
  44 static int sun4v_wdt_ping(struct watchdog_device *wdd)
  45 {
  46         int hverr;
  47 
  48         /*
  49          * HV watchdog timer will round up the timeout
  50          * passed in to the nearest multiple of the
  51          * watchdog resolution in milliseconds.
  52          */
  53         hverr = sun4v_mach_set_watchdog(wdd->timeout * 1000, NULL);
  54         if (hverr == HV_EINVAL)
  55                 return -EINVAL;
  56 
  57         return 0;
  58 }
  59 
  60 static int sun4v_wdt_set_timeout(struct watchdog_device *wdd,
  61                                  unsigned int timeout)
  62 {
  63         wdd->timeout = timeout;
  64 
  65         return 0;
  66 }
  67 
  68 static const struct watchdog_info sun4v_wdt_ident = {
  69         .options =      WDIOF_SETTIMEOUT |
  70                         WDIOF_MAGICCLOSE |
  71                         WDIOF_KEEPALIVEPING,
  72         .identity =     "sun4v hypervisor watchdog",
  73         .firmware_version = 0,
  74 };
  75 
  76 static const struct watchdog_ops sun4v_wdt_ops = {
  77         .owner =        THIS_MODULE,
  78         .start =        sun4v_wdt_ping,
  79         .stop =         sun4v_wdt_stop,
  80         .ping =         sun4v_wdt_ping,
  81         .set_timeout =  sun4v_wdt_set_timeout,
  82 };
  83 
  84 static struct watchdog_device wdd = {
  85         .info = &sun4v_wdt_ident,
  86         .ops = &sun4v_wdt_ops,
  87         .min_timeout = WDT_MIN_TIMEOUT,
  88         .max_timeout = WDT_MAX_TIMEOUT,
  89         .timeout = WDT_TIMEOUT,
  90 };
  91 
  92 static int __init sun4v_wdt_init(void)
  93 {
  94         struct mdesc_handle *handle;
  95         u64 node;
  96         const u64 *value;
  97         int err = 0;
  98         unsigned long major = 1, minor = 1;
  99 
 100         /*
 101          * There are 2 properties that can be set from the control
 102          * domain for the watchdog.
 103          * watchdog-resolution
 104          * watchdog-max-timeout
 105          *
 106          * We can expect a handle to be returned otherwise something
 107          * serious is wrong. Correct to return -ENODEV here.
 108          */
 109 
 110         handle = mdesc_grab();
 111         if (!handle)
 112                 return -ENODEV;
 113 
 114         node = mdesc_node_by_name(handle, MDESC_NODE_NULL, "platform");
 115         err = -ENODEV;
 116         if (node == MDESC_NODE_NULL)
 117                 goto out_release;
 118 
 119         /*
 120          * This is a safe way to validate if we are on the right
 121          * platform.
 122          */
 123         if (sun4v_hvapi_register(HV_GRP_CORE, major, &minor))
 124                 goto out_hv_unreg;
 125 
 126         /* Allow value of watchdog-resolution up to 1s (default) */
 127         value = mdesc_get_property(handle, node, "watchdog-resolution", NULL);
 128         err = -EINVAL;
 129         if (value) {
 130                 if (*value == 0 ||
 131                     *value > WDT_DEFAULT_RESOLUTION_MS)
 132                         goto out_hv_unreg;
 133         }
 134 
 135         value = mdesc_get_property(handle, node, "watchdog-max-timeout", NULL);
 136         if (value) {
 137                 /*
 138                  * If the property value (in ms) is smaller than
 139                  * min_timeout, return -EINVAL.
 140                  */
 141                 if (*value < wdd.min_timeout * 1000)
 142                         goto out_hv_unreg;
 143 
 144                 /*
 145                  * If the property value is smaller than
 146                  * default max_timeout  then set watchdog max_timeout to
 147                  * the value of the property in seconds.
 148                  */
 149                 if (*value < wdd.max_timeout * 1000)
 150                         wdd.max_timeout = *value  / 1000;
 151         }
 152 
 153         watchdog_init_timeout(&wdd, timeout, NULL);
 154 
 155         watchdog_set_nowayout(&wdd, nowayout);
 156 
 157         err = watchdog_register_device(&wdd);
 158         if (err)
 159                 goto out_hv_unreg;
 160 
 161         pr_info("initialized (timeout=%ds, nowayout=%d)\n",
 162                  wdd.timeout, nowayout);
 163 
 164         mdesc_release(handle);
 165 
 166         return 0;
 167 
 168 out_hv_unreg:
 169         sun4v_hvapi_unregister(HV_GRP_CORE);
 170 
 171 out_release:
 172         mdesc_release(handle);
 173         return err;
 174 }
 175 
 176 static void __exit sun4v_wdt_exit(void)
 177 {
 178         sun4v_hvapi_unregister(HV_GRP_CORE);
 179         watchdog_unregister_device(&wdd);
 180 }
 181 
 182 module_init(sun4v_wdt_init);
 183 module_exit(sun4v_wdt_exit);
 184 
 185 MODULE_AUTHOR("Wim Coekaerts <wim.coekaerts@oracle.com>");
 186 MODULE_DESCRIPTION("sun4v watchdog driver");
 187 MODULE_LICENSE("GPL");

/* [<][>][^][v][top][bottom][index][help] */