aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAlan Cox <alan@linux.intel.com>2012-02-28 17:48:11 -0500
committerWim Van Sebroeck <wim@iguana.be>2012-03-27 14:07:21 -0400
commita5132cafc0a739107e51494b9054c0066802b8cd (patch)
tree8f224cb90e877ea1cc67170f47692d2b81c4d33a
parenta0f3683365513c052d21991fe75eccd95aba9d34 (diff)
watchdog: softdog: convert to watchdog core
Convert softdog.c to the new watchdog API. Signed-off-by: Alan Cox <alan@linux.intel.com> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
-rw-r--r--drivers/watchdog/Kconfig1
-rw-r--r--drivers/watchdog/softdog.c182
2 files changed, 37 insertions, 146 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 8f5c31763286..af7444188f5c 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -55,6 +55,7 @@ comment "Watchdog Device Drivers"
55 55
56config SOFT_WATCHDOG 56config SOFT_WATCHDOG
57 tristate "Software watchdog" 57 tristate "Software watchdog"
58 select WATCHDOG_CORE
58 help 59 help
59 A software monitoring watchdog. This will fail to reboot your system 60 A software monitoring watchdog. This will fail to reboot your system
60 from some situations that the hardware watchdog will recover 61 from some situations that the hardware watchdog will recover
diff --git a/drivers/watchdog/softdog.c b/drivers/watchdog/softdog.c
index da8620f829b2..fe83beb8f1b7 100644
--- a/drivers/watchdog/softdog.c
+++ b/drivers/watchdog/softdog.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * SoftDog 0.07: A Software Watchdog Device 2 * SoftDog: A Software Watchdog Device
3 * 3 *
4 * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>, 4 * (c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
5 * All Rights Reserved. 5 * All Rights Reserved.
@@ -44,17 +44,15 @@
44#include <linux/timer.h> 44#include <linux/timer.h>
45#include <linux/miscdevice.h> 45#include <linux/miscdevice.h>
46#include <linux/watchdog.h> 46#include <linux/watchdog.h>
47#include <linux/fs.h>
48#include <linux/notifier.h> 47#include <linux/notifier.h>
49#include <linux/reboot.h> 48#include <linux/reboot.h>
50#include <linux/init.h> 49#include <linux/init.h>
51#include <linux/jiffies.h> 50#include <linux/jiffies.h>
52#include <linux/uaccess.h>
53#include <linux/kernel.h> 51#include <linux/kernel.h>
54 52
55#define TIMER_MARGIN 60 /* Default is 60 seconds */ 53#define TIMER_MARGIN 60 /* Default is 60 seconds */
56static int soft_margin = TIMER_MARGIN; /* in seconds */ 54static unsigned int soft_margin = TIMER_MARGIN; /* in seconds */
57module_param(soft_margin, int, 0); 55module_param(soft_margin, uint, 0);
58MODULE_PARM_DESC(soft_margin, 56MODULE_PARM_DESC(soft_margin,
59 "Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default=" 57 "Watchdog soft_margin in seconds. (0 < soft_margin < 65536, default="
60 __MODULE_STRING(TIMER_MARGIN) ")"); 58 __MODULE_STRING(TIMER_MARGIN) ")");
@@ -65,16 +63,10 @@ MODULE_PARM_DESC(nowayout,
65 "Watchdog cannot be stopped once started (default=" 63 "Watchdog cannot be stopped once started (default="
66 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); 64 __MODULE_STRING(WATCHDOG_NOWAYOUT) ")");
67 65
68#ifdef ONLY_TESTING
69static int soft_noboot = 1;
70#else
71static int soft_noboot = 0; 66static int soft_noboot = 0;
72#endif /* ONLY_TESTING */
73
74module_param(soft_noboot, int, 0); 67module_param(soft_noboot, int, 0);
75MODULE_PARM_DESC(soft_noboot, 68MODULE_PARM_DESC(soft_noboot,
76 "Softdog action, set to 1 to ignore reboots, 0 to reboot " 69 "Softdog action, set to 1 to ignore reboots, 0 to reboot (default=0)");
77 "(default depends on ONLY_TESTING)");
78 70
79static int soft_panic; 71static int soft_panic;
80module_param(soft_panic, int, 0); 72module_param(soft_panic, int, 0);
@@ -89,9 +81,6 @@ static void watchdog_fire(unsigned long);
89 81
90static struct timer_list watchdog_ticktock = 82static struct timer_list watchdog_ticktock =
91 TIMER_INITIALIZER(watchdog_fire, 0, 0); 83 TIMER_INITIALIZER(watchdog_fire, 0, 0);
92static unsigned long driver_open, orphan_timer;
93static char expect_close;
94
95 84
96/* 85/*
97 * If the timer expires.. 86 * If the timer expires..
@@ -99,9 +88,6 @@ static char expect_close;
99 88
100static void watchdog_fire(unsigned long data) 89static void watchdog_fire(unsigned long data)
101{ 90{
102 if (test_and_clear_bit(0, &orphan_timer))
103 module_put(THIS_MODULE);
104
105 if (soft_noboot) 91 if (soft_noboot)
106 pr_crit("Triggered - Reboot ignored\n"); 92 pr_crit("Triggered - Reboot ignored\n");
107 else if (soft_panic) { 93 else if (soft_panic) {
@@ -118,127 +104,25 @@ static void watchdog_fire(unsigned long data)
118 * Softdog operations 104 * Softdog operations
119 */ 105 */
120 106
121static int softdog_keepalive(void) 107static int softdog_ping(struct watchdog_device *w)
122{ 108{
123 mod_timer(&watchdog_ticktock, jiffies+(soft_margin*HZ)); 109 mod_timer(&watchdog_ticktock, jiffies+(w->timeout*HZ));
124 return 0; 110 return 0;
125} 111}
126 112
127static int softdog_stop(void) 113static int softdog_stop(struct watchdog_device *w)
128{ 114{
129 del_timer(&watchdog_ticktock); 115 del_timer(&watchdog_ticktock);
130 return 0; 116 return 0;
131} 117}
132 118
133static int softdog_set_heartbeat(int t) 119static int softdog_set_timeout(struct watchdog_device *w, unsigned int t)
134{ 120{
135 if ((t < 0x0001) || (t > 0xFFFF)) 121 w->timeout = t;
136 return -EINVAL;
137
138 soft_margin = t;
139 return 0; 122 return 0;
140} 123}
141 124
142/* 125/*
143 * /dev/watchdog handling
144 */
145
146static int softdog_open(struct inode *inode, struct file *file)
147{
148 if (test_and_set_bit(0, &driver_open))
149 return -EBUSY;
150 if (!test_and_clear_bit(0, &orphan_timer))
151 __module_get(THIS_MODULE);
152 /*
153 * Activate timer
154 */
155 softdog_keepalive();
156 return nonseekable_open(inode, file);
157}
158
159static int softdog_release(struct inode *inode, struct file *file)
160{
161 /*
162 * Shut off the timer.
163 * Lock it in if it's a module and we set nowayout
164 */
165 if (expect_close == 42) {
166 softdog_stop();
167 module_put(THIS_MODULE);
168 } else {
169 pr_crit("Unexpected close, not stopping watchdog!\n");
170 set_bit(0, &orphan_timer);
171 softdog_keepalive();
172 }
173 clear_bit(0, &driver_open);
174 expect_close = 0;
175 return 0;
176}
177
178static ssize_t softdog_write(struct file *file, const char __user *data,
179 size_t len, loff_t *ppos)
180{
181 /*
182 * Refresh the timer.
183 */
184 if (len) {
185 if (!nowayout) {
186 size_t i;
187
188 /* In case it was set long ago */
189 expect_close = 0;
190
191 for (i = 0; i != len; i++) {
192 char c;
193
194 if (get_user(c, data + i))
195 return -EFAULT;
196 if (c == 'V')
197 expect_close = 42;
198 }
199 }
200 softdog_keepalive();
201 }
202 return len;
203}
204
205static long softdog_ioctl(struct file *file, unsigned int cmd,
206 unsigned long arg)
207{
208 void __user *argp = (void __user *)arg;
209 int __user *p = argp;
210 int new_margin;
211 static const struct watchdog_info ident = {
212 .options = WDIOF_SETTIMEOUT |
213 WDIOF_KEEPALIVEPING |
214 WDIOF_MAGICCLOSE,
215 .firmware_version = 0,
216 .identity = "Software Watchdog",
217 };
218 switch (cmd) {
219 case WDIOC_GETSUPPORT:
220 return copy_to_user(argp, &ident, sizeof(ident)) ? -EFAULT : 0;
221 case WDIOC_GETSTATUS:
222 case WDIOC_GETBOOTSTATUS:
223 return put_user(0, p);
224 case WDIOC_KEEPALIVE:
225 softdog_keepalive();
226 return 0;
227 case WDIOC_SETTIMEOUT:
228 if (get_user(new_margin, p))
229 return -EFAULT;
230 if (softdog_set_heartbeat(new_margin))
231 return -EINVAL;
232 softdog_keepalive();
233 /* Fall */
234 case WDIOC_GETTIMEOUT:
235 return put_user(soft_margin, p);
236 default:
237 return -ENOTTY;
238 }
239}
240
241/*
242 * Notifier for system down 126 * Notifier for system down
243 */ 127 */
244 128
@@ -247,7 +131,7 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
247{ 131{
248 if (code == SYS_DOWN || code == SYS_HALT) 132 if (code == SYS_DOWN || code == SYS_HALT)
249 /* Turn the WDT off */ 133 /* Turn the WDT off */
250 softdog_stop(); 134 softdog_stop(NULL);
251 return NOTIFY_DONE; 135 return NOTIFY_DONE;
252} 136}
253 137
@@ -255,23 +139,28 @@ static int softdog_notify_sys(struct notifier_block *this, unsigned long code,
255 * Kernel Interfaces 139 * Kernel Interfaces
256 */ 140 */
257 141
258static const struct file_operations softdog_fops = { 142static struct notifier_block softdog_notifier = {
259 .owner = THIS_MODULE, 143 .notifier_call = softdog_notify_sys,
260 .llseek = no_llseek,
261 .write = softdog_write,
262 .unlocked_ioctl = softdog_ioctl,
263 .open = softdog_open,
264 .release = softdog_release,
265}; 144};
266 145
267static struct miscdevice softdog_miscdev = { 146static struct watchdog_info softdog_info = {
268 .minor = WATCHDOG_MINOR, 147 .identity = "Software Watchdog",
269 .name = "watchdog", 148 .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE,
270 .fops = &softdog_fops,
271}; 149};
272 150
273static struct notifier_block softdog_notifier = { 151static struct watchdog_ops softdog_ops = {
274 .notifier_call = softdog_notify_sys, 152 .owner = THIS_MODULE,
153 .start = softdog_ping,
154 .stop = softdog_stop,
155 .ping = softdog_ping,
156 .set_timeout = softdog_set_timeout,
157};
158
159static struct watchdog_device softdog_dev = {
160 .info = &softdog_info,
161 .ops = &softdog_ops,
162 .min_timeout = 1,
163 .max_timeout = 0xFFFF
275}; 164};
276 165
277static int __init watchdog_init(void) 166static int __init watchdog_init(void)
@@ -280,11 +169,14 @@ static int __init watchdog_init(void)
280 169
281 /* Check that the soft_margin value is within it's range; 170 /* Check that the soft_margin value is within it's range;
282 if not reset to the default */ 171 if not reset to the default */
283 if (softdog_set_heartbeat(soft_margin)) { 172 if (soft_margin < 1 || soft_margin > 65535) {
284 softdog_set_heartbeat(TIMER_MARGIN);
285 pr_info("soft_margin must be 0 < soft_margin < 65536, using %d\n", 173 pr_info("soft_margin must be 0 < soft_margin < 65536, using %d\n",
286 TIMER_MARGIN); 174 TIMER_MARGIN);
175 return -EINVAL;
287 } 176 }
177 softdog_dev.timeout = soft_margin;
178
179 watchdog_set_nowayout(&softdog_dev, nowayout);
288 180
289 ret = register_reboot_notifier(&softdog_notifier); 181 ret = register_reboot_notifier(&softdog_notifier);
290 if (ret) { 182 if (ret) {
@@ -292,15 +184,13 @@ static int __init watchdog_init(void)
292 return ret; 184 return ret;
293 } 185 }
294 186
295 ret = misc_register(&softdog_miscdev); 187 ret = watchdog_register_device(&softdog_dev);
296 if (ret) { 188 if (ret) {
297 pr_err("cannot register miscdev on minor=%d (err=%d)\n",
298 WATCHDOG_MINOR, ret);
299 unregister_reboot_notifier(&softdog_notifier); 189 unregister_reboot_notifier(&softdog_notifier);
300 return ret; 190 return ret;
301 } 191 }
302 192
303 pr_info("Software Watchdog Timer: 0.07 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout= %d)\n", 193 pr_info("Software Watchdog Timer: 0.08 initialized. soft_noboot=%d soft_margin=%d sec soft_panic=%d (nowayout=%d)\n",
304 soft_noboot, soft_margin, soft_panic, nowayout); 194 soft_noboot, soft_margin, soft_panic, nowayout);
305 195
306 return 0; 196 return 0;
@@ -308,7 +198,7 @@ static int __init watchdog_init(void)
308 198
309static void __exit watchdog_exit(void) 199static void __exit watchdog_exit(void)
310{ 200{
311 misc_deregister(&softdog_miscdev); 201 watchdog_unregister_device(&softdog_dev);
312 unregister_reboot_notifier(&softdog_notifier); 202 unregister_reboot_notifier(&softdog_notifier);
313} 203}
314 204