1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2015-2016 Mentor Graphics
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_pretimeout.h"
14 /* Default watchdog pretimeout governor */
15 static struct watchdog_governor
*default_gov
;
17 /* The spinlock protects default_gov, wdd->gov and pretimeout_list */
18 static DEFINE_SPINLOCK(pretimeout_lock
);
20 /* List of watchdog devices, which can generate a pretimeout event */
21 static LIST_HEAD(pretimeout_list
);
23 struct watchdog_pretimeout
{
24 struct watchdog_device
*wdd
;
25 struct list_head entry
;
28 /* The mutex protects governor list and serializes external interfaces */
29 static DEFINE_MUTEX(governor_lock
);
31 /* List of the registered watchdog pretimeout governors */
32 static LIST_HEAD(governor_list
);
34 struct governor_priv
{
35 struct watchdog_governor
*gov
;
36 struct list_head entry
;
39 static struct governor_priv
*find_governor_by_name(const char *gov_name
)
41 struct governor_priv
*priv
;
43 list_for_each_entry(priv
, &governor_list
, entry
)
44 if (sysfs_streq(gov_name
, priv
->gov
->name
))
50 int watchdog_pretimeout_available_governors_get(char *buf
)
52 struct governor_priv
*priv
;
55 mutex_lock(&governor_lock
);
57 list_for_each_entry(priv
, &governor_list
, entry
)
58 count
+= sprintf(buf
+ count
, "%s\n", priv
->gov
->name
);
60 mutex_unlock(&governor_lock
);
65 int watchdog_pretimeout_governor_get(struct watchdog_device
*wdd
, char *buf
)
69 spin_lock_irq(&pretimeout_lock
);
71 count
= sprintf(buf
, "%s\n", wdd
->gov
->name
);
72 spin_unlock_irq(&pretimeout_lock
);
77 int watchdog_pretimeout_governor_set(struct watchdog_device
*wdd
,
80 struct governor_priv
*priv
;
82 mutex_lock(&governor_lock
);
84 priv
= find_governor_by_name(buf
);
86 mutex_unlock(&governor_lock
);
90 spin_lock_irq(&pretimeout_lock
);
92 spin_unlock_irq(&pretimeout_lock
);
94 mutex_unlock(&governor_lock
);
99 void watchdog_notify_pretimeout(struct watchdog_device
*wdd
)
103 spin_lock_irqsave(&pretimeout_lock
, flags
);
105 spin_unlock_irqrestore(&pretimeout_lock
, flags
);
109 wdd
->gov
->pretimeout(wdd
);
110 spin_unlock_irqrestore(&pretimeout_lock
, flags
);
112 EXPORT_SYMBOL_GPL(watchdog_notify_pretimeout
);
114 int watchdog_register_governor(struct watchdog_governor
*gov
)
116 struct watchdog_pretimeout
*p
;
117 struct governor_priv
*priv
;
119 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
123 mutex_lock(&governor_lock
);
125 if (find_governor_by_name(gov
->name
)) {
126 mutex_unlock(&governor_lock
);
132 list_add(&priv
->entry
, &governor_list
);
134 if (!strncmp(gov
->name
, WATCHDOG_PRETIMEOUT_DEFAULT_GOV
,
135 WATCHDOG_GOV_NAME_MAXLEN
)) {
136 spin_lock_irq(&pretimeout_lock
);
139 list_for_each_entry(p
, &pretimeout_list
, entry
)
141 p
->wdd
->gov
= default_gov
;
142 spin_unlock_irq(&pretimeout_lock
);
145 mutex_unlock(&governor_lock
);
149 EXPORT_SYMBOL(watchdog_register_governor
);
151 void watchdog_unregister_governor(struct watchdog_governor
*gov
)
153 struct watchdog_pretimeout
*p
;
154 struct governor_priv
*priv
, *t
;
156 mutex_lock(&governor_lock
);
158 list_for_each_entry_safe(priv
, t
, &governor_list
, entry
) {
159 if (priv
->gov
== gov
) {
160 list_del(&priv
->entry
);
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
);
172 mutex_unlock(&governor_lock
);
174 EXPORT_SYMBOL(watchdog_unregister_governor
);
176 int watchdog_register_pretimeout(struct watchdog_device
*wdd
)
178 struct watchdog_pretimeout
*p
;
180 if (!(wdd
->info
->options
& WDIOF_PRETIMEOUT
))
183 p
= kzalloc(sizeof(*p
), GFP_KERNEL
);
187 spin_lock_irq(&pretimeout_lock
);
188 list_add(&p
->entry
, &pretimeout_list
);
190 wdd
->gov
= default_gov
;
191 spin_unlock_irq(&pretimeout_lock
);
196 void watchdog_unregister_pretimeout(struct watchdog_device
*wdd
)
198 struct watchdog_pretimeout
*p
, *t
;
200 if (!(wdd
->info
->options
& WDIOF_PRETIMEOUT
))
203 spin_lock_irq(&pretimeout_lock
);
206 list_for_each_entry_safe(p
, t
, &pretimeout_list
, entry
) {
212 spin_unlock_irq(&pretimeout_lock
);