009-1-watchdog-core-add-restart-handler-support.patch 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. From 2165bf524da5f5e496d1cdb8c5afae1345ecce1e Mon Sep 17 00:00:00 2001
  2. From: Damien Riegel <damien.riegel@savoirfairelinux.com>
  3. Date: Mon, 16 Nov 2015 12:27:59 -0500
  4. Subject: watchdog: core: add restart handler support
  5. Many watchdog drivers implement the same code to register a restart
  6. handler. This patch provides a generic way to set such a function.
  7. The patch adds a new restart watchdog operation. If a restart priority
  8. greater than 0 is needed, the driver can call
  9. watchdog_set_restart_priority to set it.
  10. Suggested-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  11. Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
  12. Reviewed-by: Guenter Roeck <linux@roeck-us.net>
  13. Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  14. Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  15. Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
  16. ---
  17. Documentation/watchdog/watchdog-kernel-api.txt | 19 ++++++++++
  18. drivers/watchdog/watchdog_core.c | 48 ++++++++++++++++++++++++++
  19. include/linux/watchdog.h | 6 ++++
  20. 3 files changed, 73 insertions(+)
  21. --- a/Documentation/watchdog/watchdog-kernel-api.txt
  22. +++ b/Documentation/watchdog/watchdog-kernel-api.txt
  23. @@ -53,6 +53,7 @@ struct watchdog_device {
  24. unsigned int timeout;
  25. unsigned int min_timeout;
  26. unsigned int max_timeout;
  27. + struct notifier_block restart_nb;
  28. void *driver_data;
  29. struct mutex lock;
  30. unsigned long status;
  31. @@ -75,6 +76,10 @@ It contains following fields:
  32. * timeout: the watchdog timer's timeout value (in seconds).
  33. * min_timeout: the watchdog timer's minimum timeout value (in seconds).
  34. * max_timeout: the watchdog timer's maximum timeout value (in seconds).
  35. +* restart_nb: notifier block that is registered for machine restart, for
  36. + internal use only. If a watchdog is capable of restarting the machine, it
  37. + should define ops->restart. Priority can be changed through
  38. + watchdog_set_restart_priority.
  39. * bootstatus: status of the device after booting (reported with watchdog
  40. WDIOF_* status bits).
  41. * driver_data: a pointer to the drivers private data of a watchdog device.
  42. @@ -100,6 +105,7 @@ struct watchdog_ops {
  43. unsigned int (*status)(struct watchdog_device *);
  44. int (*set_timeout)(struct watchdog_device *, unsigned int);
  45. unsigned int (*get_timeleft)(struct watchdog_device *);
  46. + int (*restart)(struct watchdog_device *);
  47. void (*ref)(struct watchdog_device *);
  48. void (*unref)(struct watchdog_device *);
  49. long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
  50. @@ -164,6 +170,8 @@ they are supported. These optional routi
  51. (Note: the WDIOF_SETTIMEOUT needs to be set in the options field of the
  52. watchdog's info structure).
  53. * get_timeleft: this routines returns the time that's left before a reset.
  54. +* restart: this routine restarts the machine. It returns 0 on success or a
  55. + negative errno code for failure.
  56. * ref: the operation that calls kref_get on the kref of a dynamically
  57. allocated watchdog_device struct.
  58. * unref: the operation that calls kref_put on the kref of a dynamically
  59. @@ -231,3 +239,14 @@ the device tree (if the module timeout p
  60. to set the default timeout value as timeout value in the watchdog_device and
  61. then use this function to set the user "preferred" timeout value.
  62. This routine returns zero on success and a negative errno code for failure.
  63. +
  64. +To change the priority of the restart handler the following helper should be
  65. +used:
  66. +
  67. +void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
  68. +
  69. +User should follow the following guidelines for setting the priority:
  70. +* 0: should be called in last resort, has limited restart capabilities
  71. +* 128: default restart handler, use if no other handler is expected to be
  72. + available, and/or if restart is sufficient to restart the entire system
  73. +* 255: highest priority, will preempt all other restart handlers
  74. --- a/drivers/watchdog/watchdog_core.c
  75. +++ b/drivers/watchdog/watchdog_core.c
  76. @@ -32,6 +32,7 @@
  77. #include <linux/types.h> /* For standard types */
  78. #include <linux/errno.h> /* For the -ENODEV/... values */
  79. #include <linux/kernel.h> /* For printk/panic/... */
  80. +#include <linux/reboot.h> /* For restart handler */
  81. #include <linux/watchdog.h> /* For watchdog specific items */
  82. #include <linux/init.h> /* For __init/__exit/... */
  83. #include <linux/idr.h> /* For ida_* macros */
  84. @@ -137,6 +138,41 @@ int watchdog_init_timeout(struct watchdo
  85. }
  86. EXPORT_SYMBOL_GPL(watchdog_init_timeout);
  87. +static int watchdog_restart_notifier(struct notifier_block *nb,
  88. + unsigned long action, void *data)
  89. +{
  90. + struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
  91. + restart_nb);
  92. +
  93. + int ret;
  94. +
  95. + ret = wdd->ops->restart(wdd);
  96. + if (ret)
  97. + return NOTIFY_BAD;
  98. +
  99. + return NOTIFY_DONE;
  100. +}
  101. +
  102. +/**
  103. + * watchdog_set_restart_priority - Change priority of restart handler
  104. + * @wdd: watchdog device
  105. + * @priority: priority of the restart handler, should follow these guidelines:
  106. + * 0: use watchdog's restart function as last resort, has limited restart
  107. + * capabilies
  108. + * 128: default restart handler, use if no other handler is expected to be
  109. + * available and/or if restart is sufficient to restart the entire system
  110. + * 255: preempt all other handlers
  111. + *
  112. + * If a wdd->ops->restart function is provided when watchdog_register_device is
  113. + * called, it will be registered as a restart handler with the priority given
  114. + * here.
  115. + */
  116. +void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority)
  117. +{
  118. + wdd->restart_nb.priority = priority;
  119. +}
  120. +EXPORT_SYMBOL_GPL(watchdog_set_restart_priority);
  121. +
  122. static int __watchdog_register_device(struct watchdog_device *wdd)
  123. {
  124. int ret, id = -1, devno;
  125. @@ -202,6 +238,15 @@ static int __watchdog_register_device(st
  126. return ret;
  127. }
  128. + if (wdd->ops->restart) {
  129. + wdd->restart_nb.notifier_call = watchdog_restart_notifier;
  130. +
  131. + ret = register_restart_handler(&wdd->restart_nb);
  132. + if (ret)
  133. + dev_warn(wdd->dev, "Cannot register restart handler (%d)\n",
  134. + ret);
  135. + }
  136. +
  137. return 0;
  138. }
  139. @@ -238,6 +283,9 @@ static void __watchdog_unregister_device
  140. if (wdd == NULL)
  141. return;
  142. + if (wdd->ops->restart)
  143. + unregister_restart_handler(&wdd->restart_nb);
  144. +
  145. devno = wdd->cdev.dev;
  146. ret = watchdog_dev_unregister(wdd);
  147. if (ret)
  148. --- a/include/linux/watchdog.h
  149. +++ b/include/linux/watchdog.h
  150. @@ -12,6 +12,7 @@
  151. #include <linux/bitops.h>
  152. #include <linux/device.h>
  153. #include <linux/cdev.h>
  154. +#include <linux/notifier.h>
  155. #include <uapi/linux/watchdog.h>
  156. struct watchdog_ops;
  157. @@ -26,6 +27,7 @@ struct watchdog_device;
  158. * @status: The routine that shows the status of the watchdog device.
  159. * @set_timeout:The routine for setting the watchdog devices timeout value (in seconds).
  160. * @get_timeleft:The routine that gets the time left before a reset (in seconds).
  161. + * @restart: The routine for restarting the machine.
  162. * @ref: The ref operation for dyn. allocated watchdog_device structs
  163. * @unref: The unref operation for dyn. allocated watchdog_device structs
  164. * @ioctl: The routines that handles extra ioctl calls.
  165. @@ -45,6 +47,7 @@ struct watchdog_ops {
  166. unsigned int (*status)(struct watchdog_device *);
  167. int (*set_timeout)(struct watchdog_device *, unsigned int);
  168. unsigned int (*get_timeleft)(struct watchdog_device *);
  169. + int (*restart)(struct watchdog_device *);
  170. void (*ref)(struct watchdog_device *);
  171. void (*unref)(struct watchdog_device *);
  172. long (*ioctl)(struct watchdog_device *, unsigned int, unsigned long);
  173. @@ -62,6 +65,7 @@ struct watchdog_ops {
  174. * @timeout: The watchdog devices timeout value (in seconds).
  175. * @min_timeout:The watchdog devices minimum timeout value (in seconds).
  176. * @max_timeout:The watchdog devices maximum timeout value (in seconds).
  177. + * @restart_nb: The notifier block to register a restart function.
  178. * @driver-data:Pointer to the drivers private data.
  179. * @lock: Lock for watchdog core internal use only.
  180. * @status: Field that contains the devices internal status bits.
  181. @@ -88,6 +92,7 @@ struct watchdog_device {
  182. unsigned int timeout;
  183. unsigned int min_timeout;
  184. unsigned int max_timeout;
  185. + struct notifier_block restart_nb;
  186. void *driver_data;
  187. struct mutex lock;
  188. unsigned long status;
  189. @@ -142,6 +147,7 @@ static inline void *watchdog_get_drvdata
  190. }
  191. /* drivers/watchdog/watchdog_core.c */
  192. +void watchdog_set_restart_priority(struct watchdog_device *wdd, int priority);
  193. extern int watchdog_init_timeout(struct watchdog_device *wdd,
  194. unsigned int timeout_parm, struct device *dev);
  195. extern int watchdog_register_device(struct watchdog_device *);