xref: /linux/drivers/watchdog/watchdog_pretimeout.c (revision 877d94c74e4c6665d2af55c0154363b43b947e60)
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