Linux 4.19.133
[linux/fpc-iii.git] / drivers / watchdog / watchdog_pretimeout.c
blob9db07bfb4334fa91428aa0909e9e890a592079ad
1 /*
2 * Copyright (C) 2015-2016 Mentor Graphics
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.
9 */
11 #include <linux/list.h>
12 #include <linux/slab.h>
13 #include <linux/spinlock.h>
14 #include <linux/string.h>
15 #include <linux/watchdog.h>
17 #include "watchdog_pretimeout.h"
19 /* Default watchdog pretimeout governor */
20 static struct watchdog_governor *default_gov;
22 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
23 static DEFINE_SPINLOCK(pretimeout_lock);
25 /* List of watchdog devices, which can generate a pretimeout event */
26 static LIST_HEAD(pretimeout_list);
28 struct watchdog_pretimeout {
29 struct watchdog_device *wdd;
30 struct list_head entry;
33 /* The mutex protects governor list and serializes external interfaces */
34 static DEFINE_MUTEX(governor_lock);
36 /* List of the registered watchdog pretimeout governors */
37 static LIST_HEAD(governor_list);
39 struct governor_priv {
40 struct watchdog_governor *gov;
41 struct list_head entry;
44 static struct governor_priv *find_governor_by_name(const char *gov_name)
46 struct governor_priv *priv;
48 list_for_each_entry(priv, &governor_list, entry)
49 if (sysfs_streq(gov_name, priv->gov->name))
50 return priv;
52 return NULL;
55 int watchdog_pretimeout_available_governors_get(char *buf)
57 struct governor_priv *priv;
58 int count = 0;
60 mutex_lock(&governor_lock);
62 list_for_each_entry(priv, &governor_list, entry)
63 count += sprintf(buf + count, "%s\n", priv->gov->name);
65 mutex_unlock(&governor_lock);
67 return count;
70 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
72 int count = 0;
74 spin_lock_irq(&pretimeout_lock);
75 if (wdd->gov)
76 count = sprintf(buf, "%s\n", wdd->gov->name);
77 spin_unlock_irq(&pretimeout_lock);
79 return count;
82 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
83 const char *buf)
85 struct governor_priv *priv;
87 mutex_lock(&governor_lock);
89 priv = find_governor_by_name(buf);
90 if (!priv) {
91 mutex_unlock(&governor_lock);
92 return -EINVAL;
95 spin_lock_irq(&pretimeout_lock);
96 wdd->gov = priv->gov;
97 spin_unlock_irq(&pretimeout_lock);
99 mutex_unlock(&governor_lock);
101 return 0;
104 void watchdog_notify_pretimeout(struct watchdog_device *wdd)
106 unsigned long flags;
108 spin_lock_irqsave(&pretimeout_lock, flags);
109 if (!wdd->gov) {
110 spin_unlock_irqrestore(&pretimeout_lock, flags);
111 return;
114 wdd->gov->pretimeout(wdd);
115 spin_unlock_irqrestore(&pretimeout_lock, flags);
117 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
119 int watchdog_register_governor(struct watchdog_governor *gov)
121 struct watchdog_pretimeout *p;
122 struct governor_priv *priv;
124 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
125 if (!priv)
126 return -ENOMEM;
128 mutex_lock(&governor_lock);
130 if (find_governor_by_name(gov->name)) {
131 mutex_unlock(&governor_lock);
132 kfree(priv);
133 return -EBUSY;
136 priv->gov = gov;
137 list_add(&priv->entry, &governor_list);
139 if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
140 WATCHDOG_GOV_NAME_MAXLEN)) {
141 spin_lock_irq(&pretimeout_lock);
142 default_gov = gov;
144 list_for_each_entry(p, &pretimeout_list, entry)
145 if (!p->wdd->gov)
146 p->wdd->gov = default_gov;
147 spin_unlock_irq(&pretimeout_lock);
150 mutex_unlock(&governor_lock);
152 return 0;
154 EXPORT_SYMBOL(watchdog_register_governor);
156 void watchdog_unregister_governor(struct watchdog_governor *gov)
158 struct watchdog_pretimeout *p;
159 struct governor_priv *priv, *t;
161 mutex_lock(&governor_lock);
163 list_for_each_entry_safe(priv, t, &governor_list, entry) {
164 if (priv->gov == gov) {
165 list_del(&priv->entry);
166 kfree(priv);
167 break;
171 spin_lock_irq(&pretimeout_lock);
172 list_for_each_entry(p, &pretimeout_list, entry)
173 if (p->wdd->gov == gov)
174 p->wdd->gov = default_gov;
175 spin_unlock_irq(&pretimeout_lock);
177 mutex_unlock(&governor_lock);
179 EXPORT_SYMBOL(watchdog_unregister_governor);
181 int watchdog_register_pretimeout(struct watchdog_device *wdd)
183 struct watchdog_pretimeout *p;
185 if (!(wdd->info->options & WDIOF_PRETIMEOUT))
186 return 0;
188 p = kzalloc(sizeof(*p), GFP_KERNEL);
189 if (!p)
190 return -ENOMEM;
192 spin_lock_irq(&pretimeout_lock);
193 list_add(&p->entry, &pretimeout_list);
194 p->wdd = wdd;
195 wdd->gov = default_gov;
196 spin_unlock_irq(&pretimeout_lock);
198 return 0;
201 void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
203 struct watchdog_pretimeout *p, *t;
205 if (!(wdd->info->options & WDIOF_PRETIMEOUT))
206 return;
208 spin_lock_irq(&pretimeout_lock);
209 wdd->gov = NULL;
211 list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
212 if (p->wdd == wdd) {
213 list_del(&p->entry);
214 break;
217 spin_unlock_irq(&pretimeout_lock);
219 kfree(p);