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