1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (C) 2015-2016 Mentor Graphics 4 */ 5 6 #include <linux/list.h> 7 #include <linux/slab.h> 8 #include <linux/spinlock.h> 9 #include <linux/string.h> 10 #include <linux/watchdog.h> 11 12 #include "watchdog_core.h" 13 #include "watchdog_pretimeout.h" 14 15 /* Default watchdog pretimeout governor */ 16 static struct watchdog_governor *default_gov; 17 18 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */ 19 static DEFINE_SPINLOCK(pretimeout_lock); 20 21 /* List of watchdog devices, which can generate a pretimeout event */ 22 static LIST_HEAD(pretimeout_list); 23 24 struct watchdog_pretimeout { 25 struct watchdog_device *wdd; 26 struct list_head entry; 27 }; 28 29 /* The mutex protects governor list and serializes external interfaces */ 30 static DEFINE_MUTEX(governor_lock); 31 32 /* List of the registered watchdog pretimeout governors */ 33 static LIST_HEAD(governor_list); 34 35 struct governor_priv { 36 struct watchdog_governor *gov; 37 struct list_head entry; 38 }; 39 40 static struct governor_priv *find_governor_by_name(const char *gov_name) 41 { 42 struct governor_priv *priv; 43 44 list_for_each_entry(priv, &governor_list, entry) 45 if (sysfs_streq(gov_name, priv->gov->name)) 46 return priv; 47 48 return NULL; 49 } 50 51 int watchdog_pretimeout_available_governors_get(char *buf) 52 { 53 struct governor_priv *priv; 54 int count = 0; 55 56 mutex_lock(&governor_lock); 57 58 list_for_each_entry(priv, &governor_list, entry) 59 count += sysfs_emit_at(buf, count, "%s\n", priv->gov->name); 60 61 mutex_unlock(&governor_lock); 62 63 return count; 64 } 65 66 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf) 67 { 68 int count = 0; 69 70 spin_lock_irq(&pretimeout_lock); 71 if (wdd->gov) 72 count = sysfs_emit(buf, "%s\n", wdd->gov->name); 73 spin_unlock_irq(&pretimeout_lock); 74 75 return count; 76 } 77 78 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd, 79 const char *buf) 80 { 81 struct governor_priv *priv; 82 83 mutex_lock(&governor_lock); 84 85 priv = find_governor_by_name(buf); 86 if (!priv) { 87 mutex_unlock(&governor_lock); 88 return -EINVAL; 89 } 90 91 spin_lock_irq(&pretimeout_lock); 92 wdd->gov = priv->gov; 93 spin_unlock_irq(&pretimeout_lock); 94 95 mutex_unlock(&governor_lock); 96 97 return 0; 98 } 99 100 void watchdog_notify_pretimeout(struct watchdog_device *wdd) 101 { 102 unsigned long flags; 103 104 spin_lock_irqsave(&pretimeout_lock, flags); 105 if (!wdd->gov) { 106 spin_unlock_irqrestore(&pretimeout_lock, flags); 107 return; 108 } 109 110 wdd->gov->pretimeout(wdd); 111 spin_unlock_irqrestore(&pretimeout_lock, flags); 112 } 113 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout); 114 115 int watchdog_register_governor(struct watchdog_governor *gov) 116 { 117 struct watchdog_pretimeout *p; 118 struct governor_priv *priv; 119 120 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 121 if (!priv) 122 return -ENOMEM; 123 124 mutex_lock(&governor_lock); 125 126 if (find_governor_by_name(gov->name)) { 127 mutex_unlock(&governor_lock); 128 kfree(priv); 129 return -EBUSY; 130 } 131 132 priv->gov = gov; 133 list_add(&priv->entry, &governor_list); 134 135 if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV, 136 WATCHDOG_GOV_NAME_MAXLEN)) { 137 spin_lock_irq(&pretimeout_lock); 138 default_gov = gov; 139 140 list_for_each_entry(p, &pretimeout_list, entry) 141 if (!p->wdd->gov) 142 p->wdd->gov = default_gov; 143 spin_unlock_irq(&pretimeout_lock); 144 } 145 146 mutex_unlock(&governor_lock); 147 148 return 0; 149 } 150 EXPORT_SYMBOL(watchdog_register_governor); 151 152 void watchdog_unregister_governor(struct watchdog_governor *gov) 153 { 154 struct watchdog_pretimeout *p; 155 struct governor_priv *priv, *t; 156 157 mutex_lock(&governor_lock); 158 159 list_for_each_entry_safe(priv, t, &governor_list, entry) { 160 if (priv->gov == gov) { 161 list_del(&priv->entry); 162 kfree(priv); 163 break; 164 } 165 } 166 167 spin_lock_irq(&pretimeout_lock); 168 list_for_each_entry(p, &pretimeout_list, entry) 169 if (p->wdd->gov == gov) 170 p->wdd->gov = default_gov; 171 spin_unlock_irq(&pretimeout_lock); 172 173 mutex_unlock(&governor_lock); 174 } 175 EXPORT_SYMBOL(watchdog_unregister_governor); 176 177 int watchdog_register_pretimeout(struct watchdog_device *wdd) 178 { 179 struct watchdog_pretimeout *p; 180 181 if (!watchdog_have_pretimeout(wdd)) 182 return 0; 183 184 p = kzalloc(sizeof(*p), GFP_KERNEL); 185 if (!p) 186 return -ENOMEM; 187 188 spin_lock_irq(&pretimeout_lock); 189 list_add(&p->entry, &pretimeout_list); 190 p->wdd = wdd; 191 wdd->gov = default_gov; 192 spin_unlock_irq(&pretimeout_lock); 193 194 return 0; 195 } 196 197 void watchdog_unregister_pretimeout(struct watchdog_device *wdd) 198 { 199 struct watchdog_pretimeout *p, *t; 200 201 if (!watchdog_have_pretimeout(wdd)) 202 return; 203 204 spin_lock_irq(&pretimeout_lock); 205 wdd->gov = NULL; 206 207 list_for_each_entry_safe(p, t, &pretimeout_list, entry) { 208 if (p->wdd == wdd) { 209 list_del(&p->entry); 210 kfree(p); 211 break; 212 } 213 } 214 spin_unlock_irq(&pretimeout_lock); 215 } 216