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