009-2-watchdog-core-add-reboot-notifier-support.patch 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. From e131319669e0ef5e6fcd75174daeffa40492135c Mon Sep 17 00:00:00 2001
  2. From: Damien Riegel <damien.riegel@savoirfairelinux.com>
  3. Date: Fri, 20 Nov 2015 16:54:51 -0500
  4. Subject: watchdog: core: add reboot notifier support
  5. Many watchdog drivers register a reboot notifier in order to stop the
  6. watchdog on system reboot. Thus we can factorize this code in the
  7. watchdog core.
  8. For that purpose, a new notifier block is added in watchdog_device for
  9. internal use only, as well as a new watchdog_stop_on_reboot helper
  10. function.
  11. If this helper is called, watchdog core registers the related notifier
  12. block and will stop the watchdog when SYS_HALT or SYS_DOWN is received.
  13. Since this operation can be critical on some platforms, abort the device
  14. registration if the reboot notifier registration fails.
  15. Suggested-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  16. Signed-off-by: Damien Riegel <damien.riegel@savoirfairelinux.com>
  17. Reviewed-by: Vivien Didelot <vivien.didelot@savoirfairelinux.com>
  18. Signed-off-by: Guenter Roeck <linux@roeck-us.net>
  19. Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
  20. ---
  21. Documentation/watchdog/watchdog-kernel-api.txt | 8 ++++++
  22. drivers/watchdog/watchdog_core.c | 37 ++++++++++++++++++++++++++
  23. include/linux/watchdog.h | 9 +++++++
  24. 3 files changed, 54 insertions(+)
  25. --- a/Documentation/watchdog/watchdog-kernel-api.txt
  26. +++ b/Documentation/watchdog/watchdog-kernel-api.txt
  27. @@ -53,6 +53,7 @@ struct watchdog_device {
  28. unsigned int timeout;
  29. unsigned int min_timeout;
  30. unsigned int max_timeout;
  31. + struct notifier_block reboot_nb;
  32. struct notifier_block restart_nb;
  33. void *driver_data;
  34. struct mutex lock;
  35. @@ -76,6 +77,9 @@ It contains following fields:
  36. * timeout: the watchdog timer's timeout value (in seconds).
  37. * min_timeout: the watchdog timer's minimum timeout value (in seconds).
  38. * max_timeout: the watchdog timer's maximum timeout value (in seconds).
  39. +* reboot_nb: notifier block that is registered for reboot notifications, for
  40. + internal use only. If the driver calls watchdog_stop_on_reboot, watchdog core
  41. + will stop the watchdog on such notifications.
  42. * restart_nb: notifier block that is registered for machine restart, for
  43. internal use only. If a watchdog is capable of restarting the machine, it
  44. should define ops->restart. Priority can be changed through
  45. @@ -240,6 +244,10 @@ to set the default timeout value as time
  46. then use this function to set the user "preferred" timeout value.
  47. This routine returns zero on success and a negative errno code for failure.
  48. +To disable the watchdog on reboot, the user must call the following helper:
  49. +
  50. +static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd);
  51. +
  52. To change the priority of the restart handler the following helper should be
  53. used:
  54. --- a/drivers/watchdog/watchdog_core.c
  55. +++ b/drivers/watchdog/watchdog_core.c
  56. @@ -138,6 +138,25 @@ int watchdog_init_timeout(struct watchdo
  57. }
  58. EXPORT_SYMBOL_GPL(watchdog_init_timeout);
  59. +static int watchdog_reboot_notifier(struct notifier_block *nb,
  60. + unsigned long code, void *data)
  61. +{
  62. + struct watchdog_device *wdd = container_of(nb, struct watchdog_device,
  63. + reboot_nb);
  64. +
  65. + if (code == SYS_DOWN || code == SYS_HALT) {
  66. + if (watchdog_active(wdd)) {
  67. + int ret;
  68. +
  69. + ret = wdd->ops->stop(wdd);
  70. + if (ret)
  71. + return NOTIFY_BAD;
  72. + }
  73. + }
  74. +
  75. + return NOTIFY_DONE;
  76. +}
  77. +
  78. static int watchdog_restart_notifier(struct notifier_block *nb,
  79. unsigned long action, void *data)
  80. {
  81. @@ -238,6 +257,21 @@ static int __watchdog_register_device(st
  82. return ret;
  83. }
  84. + if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status)) {
  85. + wdd->reboot_nb.notifier_call = watchdog_reboot_notifier;
  86. +
  87. + ret = register_reboot_notifier(&wdd->reboot_nb);
  88. + if (ret) {
  89. + dev_err(wdd->dev, "Cannot register reboot notifier (%d)\n",
  90. + ret);
  91. + watchdog_dev_unregister(wdd);
  92. + device_destroy(watchdog_class, devno);
  93. + ida_simple_remove(&watchdog_ida, wdd->id);
  94. + wdd->dev = NULL;
  95. + return ret;
  96. + }
  97. + }
  98. +
  99. if (wdd->ops->restart) {
  100. wdd->restart_nb.notifier_call = watchdog_restart_notifier;
  101. @@ -286,6 +320,9 @@ static void __watchdog_unregister_device
  102. if (wdd->ops->restart)
  103. unregister_restart_handler(&wdd->restart_nb);
  104. + if (test_bit(WDOG_STOP_ON_REBOOT, &wdd->status))
  105. + unregister_reboot_notifier(&wdd->reboot_nb);
  106. +
  107. devno = wdd->cdev.dev;
  108. ret = watchdog_dev_unregister(wdd);
  109. if (ret)
  110. --- a/include/linux/watchdog.h
  111. +++ b/include/linux/watchdog.h
  112. @@ -65,6 +65,7 @@ struct watchdog_ops {
  113. * @timeout: The watchdog devices timeout value (in seconds).
  114. * @min_timeout:The watchdog devices minimum timeout value (in seconds).
  115. * @max_timeout:The watchdog devices maximum timeout value (in seconds).
  116. + * @reboot_nb: The notifier block to stop watchdog on reboot.
  117. * @restart_nb: The notifier block to register a restart function.
  118. * @driver-data:Pointer to the drivers private data.
  119. * @lock: Lock for watchdog core internal use only.
  120. @@ -92,6 +93,7 @@ struct watchdog_device {
  121. unsigned int timeout;
  122. unsigned int min_timeout;
  123. unsigned int max_timeout;
  124. + struct notifier_block reboot_nb;
  125. struct notifier_block restart_nb;
  126. void *driver_data;
  127. struct mutex lock;
  128. @@ -102,6 +104,7 @@ struct watchdog_device {
  129. #define WDOG_ALLOW_RELEASE 2 /* Did we receive the magic char ? */
  130. #define WDOG_NO_WAY_OUT 3 /* Is 'nowayout' feature set ? */
  131. #define WDOG_UNREGISTERED 4 /* Has the device been unregistered */
  132. +#define WDOG_STOP_ON_REBOOT 5 /* Should be stopped on reboot */
  133. struct list_head deferred;
  134. };
  135. @@ -121,6 +124,12 @@ static inline void watchdog_set_nowayout
  136. set_bit(WDOG_NO_WAY_OUT, &wdd->status);
  137. }
  138. +/* Use the following function to stop the watchdog on reboot */
  139. +static inline void watchdog_stop_on_reboot(struct watchdog_device *wdd)
  140. +{
  141. + set_bit(WDOG_STOP_ON_REBOOT, &wdd->status);
  142. +}
  143. +
  144. /* Use the following function to check if a timeout value is invalid */
  145. static inline bool watchdog_timeout_invalid(struct watchdog_device *wdd, unsigned int t)
  146. {