watchdog: it8712f_wdt: remove definition of DEBUG
[sfrench/cifs-2.6.git] / drivers / watchdog / watchdog_pretimeout.c
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/watchdog.h>
11
12 #include "watchdog_pretimeout.h"
13
14 /* Default watchdog pretimeout governor */
15 static struct watchdog_governor *default_gov;
16
17 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
18 static DEFINE_SPINLOCK(pretimeout_lock);
19
20 /* List of watchdog devices, which can generate a pretimeout event */
21 static LIST_HEAD(pretimeout_list);
22
23 struct watchdog_pretimeout {
24         struct watchdog_device          *wdd;
25         struct list_head                entry;
26 };
27
28 /* The mutex protects governor list and serializes external interfaces */
29 static DEFINE_MUTEX(governor_lock);
30
31 /* List of the registered watchdog pretimeout governors */
32 static LIST_HEAD(governor_list);
33
34 struct governor_priv {
35         struct watchdog_governor        *gov;
36         struct list_head                entry;
37 };
38
39 static struct governor_priv *find_governor_by_name(const char *gov_name)
40 {
41         struct governor_priv *priv;
42
43         list_for_each_entry(priv, &governor_list, entry)
44                 if (sysfs_streq(gov_name, priv->gov->name))
45                         return priv;
46
47         return NULL;
48 }
49
50 int watchdog_pretimeout_available_governors_get(char *buf)
51 {
52         struct governor_priv *priv;
53         int count = 0;
54
55         mutex_lock(&governor_lock);
56
57         list_for_each_entry(priv, &governor_list, entry)
58                 count += sprintf(buf + count, "%s\n", priv->gov->name);
59
60         mutex_unlock(&governor_lock);
61
62         return count;
63 }
64
65 int watchdog_pretimeout_governor_get(struct watchdog_device *wdd, char *buf)
66 {
67         int count = 0;
68
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);
73
74         return count;
75 }
76
77 int watchdog_pretimeout_governor_set(struct watchdog_device *wdd,
78                                      const char *buf)
79 {
80         struct governor_priv *priv;
81
82         mutex_lock(&governor_lock);
83
84         priv = find_governor_by_name(buf);
85         if (!priv) {
86                 mutex_unlock(&governor_lock);
87                 return -EINVAL;
88         }
89
90         spin_lock_irq(&pretimeout_lock);
91         wdd->gov = priv->gov;
92         spin_unlock_irq(&pretimeout_lock);
93
94         mutex_unlock(&governor_lock);
95
96         return 0;
97 }
98
99 void watchdog_notify_pretimeout(struct watchdog_device *wdd)
100 {
101         unsigned long flags;
102
103         spin_lock_irqsave(&pretimeout_lock, flags);
104         if (!wdd->gov) {
105                 spin_unlock_irqrestore(&pretimeout_lock, flags);
106                 return;
107         }
108
109         wdd->gov->pretimeout(wdd);
110         spin_unlock_irqrestore(&pretimeout_lock, flags);
111 }
112 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout);
113
114 int watchdog_register_governor(struct watchdog_governor *gov)
115 {
116         struct watchdog_pretimeout *p;
117         struct governor_priv *priv;
118
119         priv = kzalloc(sizeof(*priv), GFP_KERNEL);
120         if (!priv)
121                 return -ENOMEM;
122
123         mutex_lock(&governor_lock);
124
125         if (find_governor_by_name(gov->name)) {
126                 mutex_unlock(&governor_lock);
127                 kfree(priv);
128                 return -EBUSY;
129         }
130
131         priv->gov = gov;
132         list_add(&priv->entry, &governor_list);
133
134         if (!strncmp(gov->name, WATCHDOG_PRETIMEOUT_DEFAULT_GOV,
135                      WATCHDOG_GOV_NAME_MAXLEN)) {
136                 spin_lock_irq(&pretimeout_lock);
137                 default_gov = gov;
138
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);
143         }
144
145         mutex_unlock(&governor_lock);
146
147         return 0;
148 }
149 EXPORT_SYMBOL(watchdog_register_governor);
150
151 void watchdog_unregister_governor(struct watchdog_governor *gov)
152 {
153         struct watchdog_pretimeout *p;
154         struct governor_priv *priv, *t;
155
156         mutex_lock(&governor_lock);
157
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;
163                 }
164         }
165
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);
171
172         mutex_unlock(&governor_lock);
173 }
174 EXPORT_SYMBOL(watchdog_unregister_governor);
175
176 int watchdog_register_pretimeout(struct watchdog_device *wdd)
177 {
178         struct watchdog_pretimeout *p;
179
180         if (!(wdd->info->options & WDIOF_PRETIMEOUT))
181                 return 0;
182
183         p = kzalloc(sizeof(*p), GFP_KERNEL);
184         if (!p)
185                 return -ENOMEM;
186
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);
192
193         return 0;
194 }
195
196 void watchdog_unregister_pretimeout(struct watchdog_device *wdd)
197 {
198         struct watchdog_pretimeout *p, *t;
199
200         if (!(wdd->info->options & WDIOF_PRETIMEOUT))
201                 return;
202
203         spin_lock_irq(&pretimeout_lock);
204         wdd->gov = NULL;
205
206         list_for_each_entry_safe(p, t, &pretimeout_list, entry) {
207                 if (p->wdd == wdd) {
208                         list_del(&p->entry);
209                         break;
210                 }
211         }
212         spin_unlock_irq(&pretimeout_lock);
213
214         kfree(p);
215 }