WIP FPC-III support
[linux/fpc-iii.git] / drivers / watchdog / watchdog_pretimeout.c
blob01ca84be240f6cfaffd61e722b9c70bf0c27c293
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (C) 2015-2016 Mentor Graphics
4 */
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>
12 #include "watchdog_pretimeout.h"
14 /* Default watchdog pretimeout governor */
15 static struct watchdog_governor *default_gov;
17 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
18 static DEFINE_SPINLOCK(pretimeout_lock);
20 /* List of watchdog devices, which can generate a pretimeout event */
21 static LIST_HEAD(pretimeout_list);
23 struct watchdog_pretimeout {
24 struct watchdog_device *wdd;
25 struct list_head entry;
28 /* The mutex protects governor list and serializes external interfaces */
29 static DEFINE_MUTEX(governor_lock);
31 /* List of the registered watchdog pretimeout governors */
32 static LIST_HEAD(governor_list);
34 struct governor_priv {
35 struct watchdog_governor *gov;
36 struct list_head entry;
39 static struct governor_priv *find_governor_by_name(const char *gov_name)
41 struct governor_priv *priv;
43 list_for_each_entry(priv, &governor_list, entry)
44 if (sysfs_streq(gov_name, priv->gov->name))
45 return priv;
47 return NULL;
50 int watchdog_pretimeout_available_governors_get(char *buf)
52 struct governor_priv *priv;
53 int count = 0;
55 mutex_lock(&governor_lock);
57 list_for_each_entry(priv, &governor_list, entry)
58 count += sprintf(buf + count, "%s\n", priv->gov->name);
60 mutex_unlock(&governor_lock);
62 return count;
65 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
67 int count = 0;
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);
74 return count;
77 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
78 const char *buf)
80 struct governor_priv *priv;
82 mutex_lock(&governor_lock);
84 priv = find_governor_by_name(buf);
85 if (!priv) {
86 mutex_unlock(&governor_lock);
87 return -EINVAL;
90 spin_lock_irq(&pretimeout_lock);
91 wdd->gov = priv->gov;
92 spin_unlock_irq(&pretimeout_lock);
94 mutex_unlock(&governor_lock);
96 return 0;
99 void watchdog_notify_pretimeout(struct watchdog_device *wdd)
101 unsigned long flags;
103 spin_lock_irqsave(&pretimeout_lock, flags);
104 if (!wdd->gov) {
105 spin_unlock_irqrestore(&pretimeout_lock, flags);
106 return;
109 wdd->gov->pretimeout(wdd);
110 spin_unlock_irqrestore(&pretimeout_lock, flags);
112 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
114 int watchdog_register_governor(struct watchdog_governor *gov)
116 struct watchdog_pretimeout *p;
117 struct governor_priv *priv;
119 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
120 if (!priv)
121 return -ENOMEM;
123 mutex_lock(&governor_lock);
125 if (find_governor_by_name(gov->name)) {
126 mutex_unlock(&governor_lock);
127 kfree(priv);
128 return -EBUSY;
131 priv->gov = gov;
132 list_add(&priv->entry, &governor_list);
134 if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
135 WATCHDOG_GOV_NAME_MAXLEN)) {
136 spin_lock_irq(&pretimeout_lock);
137 default_gov = gov;
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);
145 mutex_unlock(&governor_lock);
147 return 0;
149 EXPORT_SYMBOL(watchdog_register_governor);
151 void watchdog_unregister_governor(struct watchdog_governor *gov)
153 struct watchdog_pretimeout *p;
154 struct governor_priv *priv, *t;
156 mutex_lock(&governor_lock);
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;
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);
172 mutex_unlock(&governor_lock);
174 EXPORT_SYMBOL(watchdog_unregister_governor);
176 int watchdog_register_pretimeout(struct watchdog_device *wdd)
178 struct watchdog_pretimeout *p;
180 if (!(wdd->info->options & WDIOF_PRETIMEOUT))
181 return 0;
183 p = kzalloc(sizeof(*p), GFP_KERNEL);
184 if (!p)
185 return -ENOMEM;
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);
193 return 0;
196 void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
198 struct watchdog_pretimeout *p, *t;
200 if (!(wdd->info->options & WDIOF_PRETIMEOUT))
201 return;
203 spin_lock_irq(&pretimeout_lock);
204 wdd->gov = NULL;
206 list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
207 if (p->wdd == wdd) {
208 list_del(&p->entry);
209 break;
212 spin_unlock_irq(&pretimeout_lock);
214 kfree(p);