1 /*
2  * Copyright (C) 2015-2016 Mentor Graphics
3  *
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.
8  *
9  */
10 
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>
16 
17 #include "watchdog_pretimeout.h"
18 
19 /* Default watchdog pretimeout governor */
20 static struct watchdog_governor *default_gov;
21 
22 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
23 static DEFINE_SPINLOCK(pretimeout_lock);
24 
25 /* List of watchdog devices, which can generate a pretimeout event */
26 static LIST_HEAD(pretimeout_list);
27 
28 struct watchdog_pretimeout {
29 	struct watchdog_device		*wdd;
30 	struct list_head		entry;
31 };
32 
33 /* The mutex protects governor list and serializes external interfaces */
34 static DEFINE_MUTEX(governor_lock);
35 
36 /* List of the registered watchdog pretimeout governors */
37 static LIST_HEAD(governor_list);
38 
39 struct governor_priv {
40 	struct watchdog_governor	*gov;
41 	struct list_head		entry;
42 };
43 
44 static struct governor_priv *find_governor_by_name(const char *gov_name)
45 {
46 	struct governor_priv *priv;
47 
48 	list_for_each_entry(priv, &governor_list, entry)
49 		if (sysfs_streq(gov_name, priv->gov->name))
50 			return priv;
51 
52 	return NULL;
53 }
54 
55 int watchdog_pretimeout_available_governors_get(char *buf)
56 {
57 	struct governor_priv *priv;
58 	int count = 0;
59 
60 	mutex_lock(&governor_lock);
61 
62 	list_for_each_entry(priv, &governor_list, entry)
63 		count += sprintf(buf + count, "%s\n", priv->gov->name);
64 
65 	mutex_unlock(&governor_lock);
66 
67 	return count;
68 }
69 
70 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
71 {
72 	int count = 0;
73 
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);
78 
79 	return count;
80 }
81 
82 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
83 				     const char *buf)
84 {
85 	struct governor_priv *priv;
86 
87 	mutex_lock(&governor_lock);
88 
89 	priv = find_governor_by_name(buf);
90 	if (!priv) {
91 		mutex_unlock(&governor_lock);
92 		return -EINVAL;
93 	}
94 
95 	spin_lock_irq(&pretimeout_lock);
96 	wdd->gov = priv->gov;
97 	spin_unlock_irq(&pretimeout_lock);
98 
99 	mutex_unlock(&governor_lock);
100 
101 	return 0;
102 }
103 
104 void watchdog_notify_pretimeout(struct watchdog_device *wdd)
105 {
106 	unsigned long flags;
107 
108 	spin_lock_irqsave(&pretimeout_lock, flags);
109 	if (!wdd->gov) {
110 		spin_unlock_irqrestore(&pretimeout_lock, flags);
111 		return;
112 	}
113 
114 	wdd->gov->pretimeout(wdd);
115 	spin_unlock_irqrestore(&pretimeout_lock, flags);
116 }
117 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
118 
119 int watchdog_register_governor(struct watchdog_governor *gov)
120 {
121 	struct watchdog_pretimeout *p;
122 	struct governor_priv *priv;
123 
124 	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
125 	if (!priv)
126 		return -ENOMEM;
127 
128 	mutex_lock(&governor_lock);
129 
130 	if (find_governor_by_name(gov->name)) {
131 		mutex_unlock(&governor_lock);
132 		kfree(priv);
133 		return -EBUSY;
134 	}
135 
136 	priv->gov = gov;
137 	list_add(&priv->entry, &governor_list);
138 
139 	if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
140 		     WATCHDOG_GOV_NAME_MAXLEN)) {
141 		spin_lock_irq(&pretimeout_lock);
142 		default_gov = gov;
143 
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);
148 	}
149 
150 	mutex_unlock(&governor_lock);
151 
152 	return 0;
153 }
154 EXPORT_SYMBOL(watchdog_register_governor);
155 
156 void watchdog_unregister_governor(struct watchdog_governor *gov)
157 {
158 	struct watchdog_pretimeout *p;
159 	struct governor_priv *priv, *t;
160 
161 	mutex_lock(&governor_lock);
162 
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;
168 		}
169 	}
170 
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);
176 
177 	mutex_unlock(&governor_lock);
178 }
179 EXPORT_SYMBOL(watchdog_unregister_governor);
180 
181 int watchdog_register_pretimeout(struct watchdog_device *wdd)
182 {
183 	struct watchdog_pretimeout *p;
184 
185 	if (!(wdd->info->options & WDIOF_PRETIMEOUT))
186 		return 0;
187 
188 	p = kzalloc(sizeof(*p), GFP_KERNEL);
189 	if (!p)
190 		return -ENOMEM;
191 
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);
197 
198 	return 0;
199 }
200 
201 void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
202 {
203 	struct watchdog_pretimeout *p, *t;
204 
205 	if (!(wdd->info->options & WDIOF_PRETIMEOUT))
206 		return;
207 
208 	spin_lock_irq(&pretimeout_lock);
209 	wdd->gov = NULL;
210 
211 	list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
212 		if (p->wdd == wdd) {
213 			list_del(&p->entry);
214 			break;
215 		}
216 	}
217 	spin_unlock_irq(&pretimeout_lock);
218 
219 	kfree(p);
220 }
221