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
find_governor_by_name(const char * gov_name)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
watchdog_pretimeout_available_governors_get(char * buf)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
watchdog_pretimeout_governor_get(struct watchdog_device * wdd,char * buf)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
watchdog_pretimeout_governor_set(struct watchdog_device * wdd,const char * buf)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
watchdog_notify_pretimeout(struct watchdog_device * wdd)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
watchdog_register_governor(struct watchdog_governor * gov)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
watchdog_unregister_governor(struct watchdog_governor * gov)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
watchdog_register_pretimeout(struct watchdog_device * wdd)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
watchdog_unregister_pretimeout(struct watchdog_device * wdd)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