dma-fence: Add some more fence-merge-unwrap tests
[drm/drm-misc.git] / drivers / watchdog / watchdog_pretimeout.c
blobe5295c990fa1b8a0df328811fb061b03520da02b
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_core.h"
13 #include "watchdog_pretimeout.h"
15 /* Default watchdog pretimeout governor */
16 static struct watchdog_governor *default_gov;
18 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
19 static DEFINE_SPINLOCK(pretimeout_lock);
21 /* List of watchdog devices, which can generate a pretimeout event */
22 static LIST_HEAD(pretimeout_list);
24 struct watchdog_pretimeout {
25 struct watchdog_device *wdd;
26 struct list_head entry;
29 /* The mutex protects governor list and serializes external interfaces */
30 static DEFINE_MUTEX(governor_lock);
32 /* List of the registered watchdog pretimeout governors */
33 static LIST_HEAD(governor_list);
35 struct governor_priv {
36 struct watchdog_governor *gov;
37 struct list_head entry;
40 static struct governor_priv *find_governor_by_name(const char *gov_name)
42 struct governor_priv *priv;
44 list_for_each_entry(priv, &governor_list, entry)
45 if (sysfs_streq(gov_name, priv->gov->name))
46 return priv;
48 return NULL;
51 int watchdog_pretimeout_available_governors_get(char *buf)
53 struct governor_priv *priv;
54 int count = 0;
56 mutex_lock(&governor_lock);
58 list_for_each_entry(priv, &governor_list, entry)
59 count += sysfs_emit_at(buf, count, "%s\n", priv->gov->name);
61 mutex_unlock(&governor_lock);
63 return count;
66 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
68 int count = 0;
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);
75 return count;
78 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
79 const char *buf)
81 struct governor_priv *priv;
83 mutex_lock(&governor_lock);
85 priv = find_governor_by_name(buf);
86 if (!priv) {
87 mutex_unlock(&governor_lock);
88 return -EINVAL;
91 spin_lock_irq(&pretimeout_lock);
92 wdd->gov = priv->gov;
93 spin_unlock_irq(&pretimeout_lock);
95 mutex_unlock(&governor_lock);
97 return 0;
100 void watchdog_notify_pretimeout(struct watchdog_device *wdd)
102 unsigned long flags;
104 spin_lock_irqsave(&pretimeout_lock, flags);
105 if (!wdd->gov) {
106 spin_unlock_irqrestore(&pretimeout_lock, flags);
107 return;
110 wdd->gov->pretimeout(wdd);
111 spin_unlock_irqrestore(&pretimeout_lock, flags);
113 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
115 int watchdog_register_governor(struct watchdog_governor *gov)
117 struct watchdog_pretimeout *p;
118 struct governor_priv *priv;
120 priv = kzalloc(sizeof(*priv), GFP_KERNEL);
121 if (!priv)
122 return -ENOMEM;
124 mutex_lock(&governor_lock);
126 if (find_governor_by_name(gov->name)) {
127 mutex_unlock(&governor_lock);
128 kfree(priv);
129 return -EBUSY;
132 priv->gov = gov;
133 list_add(&priv->entry, &governor_list);
135 if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
136 WATCHDOG_GOV_NAME_MAXLEN)) {
137 spin_lock_irq(&pretimeout_lock);
138 default_gov = gov;
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);
146 mutex_unlock(&governor_lock);
148 return 0;
150 EXPORT_SYMBOL(watchdog_register_governor);
152 void watchdog_unregister_governor(struct watchdog_governor *gov)
154 struct watchdog_pretimeout *p;
155 struct governor_priv *priv, *t;
157 mutex_lock(&governor_lock);
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;
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);
173 mutex_unlock(&governor_lock);
175 EXPORT_SYMBOL(watchdog_unregister_governor);
177 int watchdog_register_pretimeout(struct watchdog_device *wdd)
179 struct watchdog_pretimeout *p;
181 if (!watchdog_have_pretimeout(wdd))
182 return 0;
184 p = kzalloc(sizeof(*p), GFP_KERNEL);
185 if (!p)
186 return -ENOMEM;
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);
194 return 0;
197 void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
199 struct watchdog_pretimeout *p, *t;
201 if (!watchdog_have_pretimeout(wdd))
202 return;
204 spin_lock_irq(&pretimeout_lock);
205 wdd->gov = NULL;
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;
214 spin_unlock_irq(&pretimeout_lock);