watchdog_pretimeout.c 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. /*
  2. * Copyright (C) 2015-2016 Mentor Graphics
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. */
  10. #include <linux/list.h>
  11. #include <linux/slab.h>
  12. #include <linux/spinlock.h>
  13. #include <linux/string.h>
  14. #include <linux/watchdog.h>
  15. #include "watchdog_pretimeout.h"
  16. /* Default watchdog pretimeout governor */
  17. static struct watchdog_governor *default_gov;
  18. /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
  19. static DEFINE_SPINLOCK(pretimeout_lock);
  20. /* List of watchdog devices, which can generate a pretimeout event */
  21. static LIST_HEAD(pretimeout_list);
  22. struct watchdog_pretimeout {
  23. struct watchdog_device *wdd;
  24. struct list_head entry;
  25. };
  26. /* The mutex protects governor list and serializes external interfaces */
  27. static DEFINE_MUTEX(governor_lock);
  28. /* List of the registered watchdog pretimeout governors */
  29. static LIST_HEAD(governor_list);
  30. struct governor_priv {
  31. struct watchdog_governor *gov;
  32. struct list_head entry;
  33. };
  34. static struct governor_priv *find_governor_by_name(const char *gov_name)
  35. {
  36. struct governor_priv *priv;
  37. list_for_each_entry(priv, &governor_list, entry)
  38. if (sysfs_streq(gov_name, priv->gov->name))
  39. return priv;
  40. return NULL;
  41. }
  42. int watchdog_pretimeout_available_governors_get(char *buf)
  43. {
  44. struct governor_priv *priv;
  45. int count = 0;
  46. mutex_lock(&governor_lock);
  47. list_for_each_entry(priv, &governor_list, entry)
  48. count += sprintf(buf + count, "%s\n", priv->gov->name);
  49. mutex_unlock(&governor_lock);
  50. return count;
  51. }
  52. int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
  53. {
  54. int count = 0;
  55. spin_lock_irq(&pretimeout_lock);
  56. if (wdd->gov)
  57. count = sprintf(buf, "%s\n", wdd->gov->name);
  58. spin_unlock_irq(&pretimeout_lock);
  59. return count;
  60. }
  61. int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
  62. const char *buf)
  63. {
  64. struct governor_priv *priv;
  65. mutex_lock(&governor_lock);
  66. priv = find_governor_by_name(buf);
  67. if (!priv) {
  68. mutex_unlock(&governor_lock);
  69. return -EINVAL;
  70. }
  71. spin_lock_irq(&pretimeout_lock);
  72. wdd->gov = priv->gov;
  73. spin_unlock_irq(&pretimeout_lock);
  74. mutex_unlock(&governor_lock);
  75. return 0;
  76. }
  77. void watchdog_notify_pretimeout(struct watchdog_device *wdd)
  78. {
  79. unsigned long flags;
  80. spin_lock_irqsave(&pretimeout_lock, flags);
  81. if (!wdd->gov) {
  82. spin_unlock_irqrestore(&pretimeout_lock, flags);
  83. return;
  84. }
  85. wdd->gov->pretimeout(wdd);
  86. spin_unlock_irqrestore(&pretimeout_lock, flags);
  87. }
  88. EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
  89. int watchdog_register_governor(struct watchdog_governor *gov)
  90. {
  91. struct watchdog_pretimeout *p;
  92. struct governor_priv *priv;
  93. priv = kzalloc(sizeof(*priv), GFP_KERNEL);
  94. if (!priv)
  95. return -ENOMEM;
  96. mutex_lock(&governor_lock);
  97. if (find_governor_by_name(gov->name)) {
  98. mutex_unlock(&governor_lock);
  99. kfree(priv);
  100. return -EBUSY;
  101. }
  102. priv->gov = gov;
  103. list_add(&priv->entry, &governor_list);
  104. if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
  105. WATCHDOG_GOV_NAME_MAXLEN)) {
  106. spin_lock_irq(&pretimeout_lock);
  107. default_gov = gov;
  108. list_for_each_entry(p, &pretimeout_list, entry)
  109. if (!p->wdd->gov)
  110. p->wdd->gov = default_gov;
  111. spin_unlock_irq(&pretimeout_lock);
  112. }
  113. mutex_unlock(&governor_lock);
  114. return 0;
  115. }
  116. EXPORT_SYMBOL(watchdog_register_governor);
  117. void watchdog_unregister_governor(struct watchdog_governor *gov)
  118. {
  119. struct watchdog_pretimeout *p;
  120. struct governor_priv *priv, *t;
  121. mutex_lock(&governor_lock);
  122. list_for_each_entry_safe(priv, t, &governor_list, entry) {
  123. if (priv->gov == gov) {
  124. list_del(&priv->entry);
  125. kfree(priv);
  126. break;
  127. }
  128. }
  129. spin_lock_irq(&pretimeout_lock);
  130. list_for_each_entry(p, &pretimeout_list, entry)
  131. if (p->wdd->gov == gov)
  132. p->wdd->gov = default_gov;
  133. spin_unlock_irq(&pretimeout_lock);
  134. mutex_unlock(&governor_lock);
  135. }
  136. EXPORT_SYMBOL(watchdog_unregister_governor);
  137. int watchdog_register_pretimeout(struct watchdog_device *wdd)
  138. {
  139. struct watchdog_pretimeout *p;
  140. if (!(wdd->info->options & WDIOF_PRETIMEOUT))
  141. return 0;
  142. p = kzalloc(sizeof(*p), GFP_KERNEL);
  143. if (!p)
  144. return -ENOMEM;
  145. spin_lock_irq(&pretimeout_lock);
  146. list_add(&p->entry, &pretimeout_list);
  147. p->wdd = wdd;
  148. wdd->gov = default_gov;
  149. spin_unlock_irq(&pretimeout_lock);
  150. return 0;
  151. }
  152. void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
  153. {
  154. struct watchdog_pretimeout *p, *t;
  155. if (!(wdd->info->options & WDIOF_PRETIMEOUT))
  156. return;
  157. spin_lock_irq(&pretimeout_lock);
  158. wdd->gov = NULL;
  159. list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
  160. if (p->wdd == wdd) {
  161. list_del(&p->entry);
  162. break;
  163. }
  164. }
  165. spin_unlock_irq(&pretimeout_lock);
  166. kfree(p);
  167. }