MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / char / snapdog.c
blob3b74dd1ee5b0da828292f92db9673bdecedaa493
1 /****************************************************************************/
2 /*
3 * SnapGear Hardware Watchdog driver (this WD cannot be stopped)
5 * Copyright 2004 David McCullough <davidm@snapgear.com>, All Rights Reserved.
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version
10 * 2 of the License, or (at your option) any later version.
12 * based on softdog.c by Alan Cox <alan@redhat.com>
14 /****************************************************************************/
16 #include <linux/module.h>
17 #include <linux/types.h>
18 #include <linux/kernel.h>
19 #include <linux/fs.h>
20 #include <linux/mm.h>
21 #include <linux/miscdevice.h>
22 #include <linux/watchdog.h>
23 #include <linux/smp_lock.h>
24 #include <linux/init.h>
25 #include <linux/reboot.h>
26 #include <asm/uaccess.h>
27 #include <asm/irq_regs.h>
29 /****************************************************************************/
31 * here we put the platform specific bits (headers/poke function)
34 #ifdef CONFIG_SH_SECUREEDGE5410
35 #include <asm/io.h>
37 static inline void enable_dog(void) {}
39 static inline void poke_the_dog(void)
41 volatile char dummy;
42 dummy = * (volatile char *) 0xb8000000;
45 static inline void the_dog_is_dead(void) {}
47 #define HAS_HW_SERVICE 1
48 #endif
50 #ifdef CONFIG_MACH_IPD
51 #include <asm/io.h>
53 static volatile char *dog_addr = NULL;
55 static inline void enable_dog(void)
57 dog_addr = (char *) ioremap(0x20000000, 32);
60 static inline void poke_the_dog(void)
62 if (dog_addr) {
63 volatile char dummy = *dog_addr;
67 static inline void the_dog_is_dead(void) {}
69 #define HAS_HW_SERVICE 1
70 #endif
72 #if defined(CONFIG_MACH_ESS710) || defined(CONFIG_MACH_IVPN) || \
73 defined(CONFIG_MACH_SG560) || defined(CONFIG_MACH_SG580) || \
74 defined(CONFIG_MACH_SG640) || defined(CONFIG_MACH_SG720) || \
75 defined(CONFIG_MACH_SG590)
76 #include <asm/io.h>
78 static inline void enable_dog(void)
80 *IXP4XX_GPIO_GPCLKR &= 0xffff0000;
83 static inline void poke_the_dog(void)
85 *IXP4XX_GPIO_GPOUTR ^= 0x4000;
88 static inline void the_dog_is_dead(void) {}
90 #define HAS_HW_SERVICE 1
91 #endif
93 #if defined(CONFIG_MACH_SG8100)
94 #include <asm/io.h>
96 static inline void enable_dog(void)
100 static inline void poke_the_dog(void)
102 *IXP4XX_GPIO_GPOUTR ^= 0x2000;
105 static inline void the_dog_is_dead(void) {}
107 #define HAS_HW_SERVICE 1
108 #endif
110 #if defined(CONFIG_MACH_SG565) || defined(CONFIG_MACH_SHIVA1100)
111 #include <asm/io.h>
113 static volatile unsigned char *wdtcs2;
115 static inline void enable_dog(void)
117 /* CS7 is watchdog alive. Set it to 8bit and writable */
118 *SG565_WATCHDOG_EXP_CS = 0xbfff0003;
119 wdtcs2 = (volatile unsigned char *) ioremap(SG565_WATCHDOG_BASE_PHYS, 512);
122 static inline void poke_the_dog(void)
124 if (wdtcs2)
125 *wdtcs2 = 0;
128 static inline void the_dog_is_dead(void) {}
130 #define HAS_HW_SERVICE 1
131 #endif
133 #ifdef CONFIG_GEODEWATCHDOG
134 #include <asm/io.h>
136 static inline void enable_dog(void) {}
138 static inline void poke_the_dog(void)
140 unsigned int v;
141 v = inl(0x6410);
142 outl((v | 0x200), 0x6410);
143 outl((v & ~0x200), 0x6410);
146 static inline void the_dog_is_dead(void) {}
148 #define HAS_HW_SERVICE 1
149 #endif
151 #ifndef HAS_HW_SERVICE
152 static inline void enable_dog(void) {}
153 static inline void poke_the_dog(void) {}
154 static inline void the_dog_is_dead(void)
156 machine_restart(NULL);
157 printk(KERN_CRIT "snapdog: reboot failed!.\n");
159 #endif
161 /****************************************************************************/
163 static unsigned long snapdog_last = 0;
164 static unsigned long snapdog_next = 0;
165 static int snapdog_service_required = 0;
166 static unsigned long snapdog_busy = 0;
167 static int snapdog_kernel = 0;
168 static int snapdog_timeout = 60;
169 static int snapdog_ltimeout = 300;
170 static int snapdog_use_long_timeout = 0;
171 static int snapdog_quiet = 0;
172 static int snapdog_warned = 0;
173 static int snapdog_stackdump = 64;
175 module_param(snapdog_kernel, int, 0);
176 MODULE_PARM_DESC(snapdog_kernel,
177 "Watchdog is kernel only (userland servicing not required)");
179 module_param(snapdog_timeout, int, 0);
180 MODULE_PARM_DESC(snapdog_timeout,
181 "Watchdog timeout for user service in seconds");
183 module_param(snapdog_ltimeout, int, 0);
184 MODULE_PARM_DESC(snapdog_ltimeout,
185 "Watchdog 'long' timeout for user service in seconds");
187 module_param(snapdog_stackdump, int, 0);
188 MODULE_PARM_DESC(snapdog_stackdump,
189 "Number of long words to dump from the stack");
191 /****************************************************************************/
193 * a really dumb stack dump, we may need better on some platforms
194 * at least this one is implemented, unlike dump_stack which is largely
195 * just a stub :-(
198 static void snapdog_show_stack(struct pt_regs *regs)
200 unsigned long i;
201 unsigned long *addr = &i;
203 printk("Kernel stack:");
204 for (i = 0; i < snapdog_stackdump; i++) {
205 if (i % 4 == 0)
206 printk("\n%08lx:", (unsigned long) addr);
207 printk(" 0x%08lx", *addr++);
209 printk("\n");
212 /****************************************************************************/
214 * Because we need to service this guy from deep in other more critical
215 * code, we export a function to do this that we can call where
216 * appropriate.
218 * Also the watchdog never stops, it is always running. We must service
219 * it until we are opened, then we stop servicing it if we are not looked
220 * after appropriately.
222 * I know there are much more clever ways to code the following, but then
223 * who would understand it, let alone know it did the right thing when
224 * jiffies wraps ;-)
227 void
228 snapdog_service(void)
230 struct pt_regs *regs;
231 int the_dog_is_alive = 0;
233 if (snapdog_kernel) {
234 the_dog_is_alive = 1;
235 } else if (!snapdog_service_required) {
236 the_dog_is_alive = 1;
237 } else if (snapdog_next < snapdog_last) {
238 if (jiffies < snapdog_next || jiffies > snapdog_last)
239 the_dog_is_alive = 1;
240 } else if (jiffies >= snapdog_last && jiffies < snapdog_next) {
241 the_dog_is_alive = 1;
244 if (the_dog_is_alive)
245 poke_the_dog();
246 else if (!snapdog_warned) {
247 snapdog_warned = 1;
248 printk(KERN_CRIT "snapdog: expired, allowing system reboot.\n");
249 regs = get_irq_regs();
250 if (regs) {
251 show_regs(regs);
252 snapdog_show_stack(regs);
254 the_dog_is_dead();
258 EXPORT_SYMBOL(snapdog_service);
260 /****************************************************************************/
262 * bump the userland expiry
265 static inline void
266 snapdog_user_service(void)
268 snapdog_last = jiffies;
269 if (snapdog_use_long_timeout)
270 snapdog_next = snapdog_last + HZ * snapdog_ltimeout;
271 else
272 snapdog_next = snapdog_last + HZ * snapdog_timeout;
273 snapdog_warned = 0;
276 /****************************************************************************/
278 * Allow only one person to hold it open
281 static int
282 snapdog_open(struct inode *inode, struct file *file)
284 if (test_and_set_bit(0, &snapdog_busy))
285 return -EBUSY;
287 /* Activate timer */
288 snapdog_service_required = 1;
289 if (snapdog_use_long_timeout) {
290 /* Opening reverts to using short timeouts */
291 snapdog_use_long_timeout = 0;
293 if (!snapdog_quiet) {
294 printk(KERN_INFO "snapdog: now using short timeouts.\n");
297 snapdog_user_service();
299 if (!snapdog_quiet) {
300 printk(KERN_INFO "snapdog: user servicing enabled (short=%d,long=%d).\n",
301 snapdog_timeout, snapdog_ltimeout);
305 /* Opening turns off quiet mode */
306 snapdog_quiet = 0;
309 return 0;
312 /****************************************************************************/
314 static int
315 snapdog_release(struct inode *inode, struct file *file)
317 lock_kernel();
318 if (!snapdog_quiet) {
319 if (!snapdog_service_required) {
320 printk(KERN_INFO
321 "snapdog: disabled user servicing of watchdog timer.\n");
322 } else if (snapdog_use_long_timeout) {
323 printk(KERN_CRIT
324 "snapdog: device closed, watchdog will reboot!\n");
327 clear_bit(0, &snapdog_busy);
328 unlock_kernel();
330 return 0;
333 /****************************************************************************/
335 static ssize_t
336 snapdog_write(struct file *file, const char __user *data, size_t len, loff_t *ppos)
338 /* Can't seek (pwrite) on this device */
339 if (*ppos != file->f_pos)
340 return -ESPIPE;
343 * Refresh the timer.
345 if (len) {
346 size_t i;
348 for (i = 0; i != len; i++) {
349 char c;
350 if (get_user(c, data + i))
351 return -EFAULT;
352 if (c == 'V') {
353 snapdog_service_required = 0;
355 else if (c == 'T') {
356 if (!snapdog_quiet) {
357 printk(KERN_INFO "snapdog: now using long timeouts.\n");
359 snapdog_use_long_timeout = 1;
361 else if (c == 'Q') {
362 /* Go quiet */
363 snapdog_quiet = 1;
366 snapdog_user_service();
367 return 1;
369 return 0;
372 /****************************************************************************/
374 static int
375 snapdog_ioctl(
376 struct inode *inode,
377 struct file *file,
378 unsigned int cmd,
379 unsigned long arg)
381 static struct watchdog_info ident = {
382 .options = WDIOF_MAGICCLOSE,
383 .identity = "HW/SW Watchdog for SnapGear",
386 switch (cmd) {
387 default:
388 return(-ENOIOCTLCMD);
390 case WDIOC_GETSUPPORT:
391 if (copy_to_user((struct watchdog_info __user *) arg, &ident, sizeof(ident)))
392 return -EFAULT;
393 return(0);
395 case WDIOC_GETSTATUS:
396 case WDIOC_GETBOOTSTATUS:
397 return(put_user(0, (int __user *) arg));
399 case WDIOC_KEEPALIVE:
400 snapdog_user_service();
401 return(0);
405 /****************************************************************************/
407 static struct file_operations snapdog_fops = {
408 .owner = THIS_MODULE,
409 .write = snapdog_write,
410 .ioctl = snapdog_ioctl,
411 .open = snapdog_open,
412 .release = snapdog_release,
416 static struct miscdevice snapdog_miscdev = {
417 .minor = WATCHDOG_MINOR,
418 .name = "watchdog",
419 .fops = &snapdog_fops,
422 /****************************************************************************/
424 static const char banner[] __initdata =
425 KERN_INFO "snapdog: HW/SW watchdog timer for SnapGear/Others\n";
427 static int __init
428 watchdog_init(void)
430 int ret;
432 enable_dog();
434 ret = misc_register(&snapdog_miscdev);
435 if (ret)
436 return ret;
438 printk(banner);
440 return 0;
443 /****************************************************************************/
445 static void __exit
446 watchdog_exit(void)
448 misc_deregister(&snapdog_miscdev);
451 /****************************************************************************/
453 module_init(watchdog_init);
454 module_exit(watchdog_exit);
455 MODULE_AUTHOR("David McCullough <davidm@snapgear.com>");
456 MODULE_DESCRIPTION("Driver for SnapGear HW/SW watchdog timer(s)");
457 MODULE_LICENSE("GPL");
459 /****************************************************************************/