Blame view

drivers/watchdog/wdt285.c 4.74 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
  /*
   *	Intel 21285 watchdog driver
   *	Copyright (c) Phil Blundell <pb@nexus.co.uk>, 1998
   *
   *	based on
   *
   *	SoftDog	0.05:	A Software Watchdog Device
   *
29fa0586d   Alan Cox   [PATCH] Switch al...
9
10
   *	(c) Copyright 1996 Alan Cox <alan@lxorguk.ukuu.org.uk>,
   *						All Rights Reserved.
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
11
12
13
14
15
16
17
   *
   *	This program is free software; you can redistribute it and/or
   *	modify it under the terms of the GNU General Public License
   *	as published by the Free Software Foundation; either version
   *	2 of the License, or (at your option) any later version.
   *
   */
27c766aaa   Joe Perches   watchdog: Use pr_...
18
  #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
19
20
21
22
23
24
25
26
27
28
29
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/fs.h>
  #include <linux/mm.h>
  #include <linux/miscdevice.h>
  #include <linux/watchdog.h>
  #include <linux/reboot.h>
  #include <linux/init.h>
  #include <linux/interrupt.h>
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
30
31
  #include <linux/uaccess.h>
  #include <linux/irq.h>
a09e64fbc   Russell King   [ARM] Move includ...
32
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
33

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
34
  #include <asm/mach-types.h>
9f97da78b   David Howells   Disintegrate asm/...
35
  #include <asm/system_info.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
  #include <asm/hardware/dec21285.h>
  
  /*
   * Define this to stop the watchdog actually rebooting the machine.
   */
  #undef ONLY_TESTING
  
  static unsigned int soft_margin = 60;		/* in seconds */
  static unsigned int reload;
  static unsigned long timer_alive;
  
  #ifdef ONLY_TESTING
  /*
   *	If the timer expires..
   */
7d12e780e   David Howells   IRQ: Maintain reg...
51
  static void watchdog_fire(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
52
  {
27c766aaa   Joe Perches   watchdog: Use pr_...
53
54
  	pr_crit("Would Reboot
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
  	*CSR_TIMER4_CNTL = 0;
  	*CSR_TIMER4_CLR = 0;
  }
  #endif
  
  /*
   *	Refresh the timer.
   */
  static void watchdog_ping(void)
  {
  	*CSR_TIMER4_LOAD = reload;
  }
  
  /*
   *	Allow only one person to hold it open
   */
  static int watchdog_open(struct inode *inode, struct file *file)
  {
  	int ret;
  
  	if (*CSR_SA110_CNTL & (1 << 13))
  		return -EBUSY;
  
  	if (test_and_set_bit(1, &timer_alive))
  		return -EBUSY;
  
  	reload = soft_margin * (mem_fclk_21285 / 256);
  
  	*CSR_TIMER4_CLR = 0;
  	watchdog_ping();
  	*CSR_TIMER4_CNTL = TIMER_CNTL_ENABLE | TIMER_CNTL_AUTORELOAD
  		| TIMER_CNTL_DIV256;
  
  #ifdef ONLY_TESTING
  	ret = request_irq(IRQ_TIMER4, watchdog_fire, 0, "watchdog", NULL);
  	if (ret) {
  		*CSR_TIMER4_CNTL = 0;
  		clear_bit(1, &timer_alive);
  	}
  #else
  	/*
  	 * Setting this bit is irreversible; once enabled, there is
  	 * no way to disable the watchdog.
  	 */
  	*CSR_SA110_CNTL |= 1 << 13;
  
  	ret = 0;
  #endif
  	nonseekable_open(inode, file);
  	return ret;
  }
  
  /*
   *	Shut off the timer.
   *	Note: if we really have enabled the watchdog, there
   *	is no way to turn off.
   */
  static int watchdog_release(struct inode *inode, struct file *file)
  {
  #ifdef ONLY_TESTING
  	free_irq(IRQ_TIMER4, NULL);
  	clear_bit(1, &timer_alive);
  #endif
  	return 0;
  }
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
120
121
  static ssize_t watchdog_write(struct file *file, const char __user *data,
  			      size_t len, loff_t *ppos)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
122
123
124
125
126
127
128
129
130
  {
  	/*
  	 *	Refresh the timer.
  	 */
  	if (len)
  		watchdog_ping();
  
  	return len;
  }
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
131
  static const struct watchdog_info ident = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
  	.options	= WDIOF_SETTIMEOUT,
  	.identity	= "Footbridge Watchdog",
  };
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
135
  static long watchdog_ioctl(struct file *file, unsigned int cmd,
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
136
  			   unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
137
  {
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
138
  	int __user *int_arg = (int __user *)arg;
70605d9ba   Alexander Shiyan   watchdog: wdt285:...
139
  	int new_margin, ret = -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
140

d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
141
  	switch (cmd) {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
142
143
  	case WDIOC_GETSUPPORT:
  		ret = 0;
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
144
  		if (copy_to_user((void __user *)arg, &ident, sizeof(ident)))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
145
146
147
148
149
  			ret = -EFAULT;
  		break;
  
  	case WDIOC_GETSTATUS:
  	case WDIOC_GETBOOTSTATUS:
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
150
  		ret = put_user(0, int_arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
151
152
153
154
155
156
157
158
  		break;
  
  	case WDIOC_KEEPALIVE:
  		watchdog_ping();
  		ret = 0;
  		break;
  
  	case WDIOC_SETTIMEOUT:
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
159
  		ret = get_user(new_margin, int_arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
160
161
162
163
164
165
166
167
168
169
170
171
172
173
  		if (ret)
  			break;
  
  		/* Arbitrary, can't find the card's limits */
  		if (new_margin < 0 || new_margin > 60) {
  			ret = -EINVAL;
  			break;
  		}
  
  		soft_margin = new_margin;
  		reload = soft_margin * (mem_fclk_21285 / 256);
  		watchdog_ping();
  		/* Fall */
  	case WDIOC_GETTIMEOUT:
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
174
  		ret = put_user(soft_margin, int_arg);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
177
178
  		break;
  	}
  	return ret;
  }
62322d255   Arjan van de Ven   [PATCH] make more...
179
  static const struct file_operations watchdog_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.write		= watchdog_write,
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
183
  	.unlocked_ioctl	= watchdog_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
  	.open		= watchdog_open,
  	.release	= watchdog_release,
  };
  
  static struct miscdevice watchdog_miscdev = {
  	.minor		= WATCHDOG_MINOR,
  	.name		= "watchdog",
  	.fops		= &watchdog_fops,
  };
  
  static int __init footbridge_watchdog_init(void)
  {
  	int retval;
  
  	if (machine_is_netwinder())
  		return -ENODEV;
  
  	retval = misc_register(&watchdog_miscdev);
  	if (retval < 0)
  		return retval;
27c766aaa   Joe Perches   watchdog: Use pr_...
204
205
206
  	pr_info("Footbridge Watchdog Timer: 0.01, timer margin: %d sec
  ",
  		soft_margin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
207
208
  
  	if (machine_is_cats())
27c766aaa   Joe Perches   watchdog: Use pr_...
209
210
  		pr_warn("Warning: Watchdog reset may not work on this machine
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
211
212
213
214
215
216
217
218
219
220
221
  	return 0;
  }
  
  static void __exit footbridge_watchdog_exit(void)
  {
  	misc_deregister(&watchdog_miscdev);
  }
  
  MODULE_AUTHOR("Phil Blundell <pb@nexus.co.uk>");
  MODULE_DESCRIPTION("Footbridge watchdog driver");
  MODULE_LICENSE("GPL");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
222
223
  
  module_param(soft_margin, int, 0);
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
224
  MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
225
226
227
  
  module_init(footbridge_watchdog_init);
  module_exit(footbridge_watchdog_exit);