sun4v_wdt.c 4.3 KB

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