Blame view

drivers/watchdog/wdt285.c 4.77 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
18
19
20
21
22
23
24
25
26
27
28
29
   *
   *	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.
   *
   */
  
  #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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
  #include <asm/mach-types.h>
  #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...
50
  static void watchdog_fire(int irq, void *dev_id)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
51
52
53
54
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
  {
  	printk(KERN_CRIT "Watchdog: Would Reboot.
  ");
  	*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...
119
120
  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
121
122
123
124
125
126
127
128
129
  {
  	/*
  	 *	Refresh the timer.
  	 */
  	if (len)
  		watchdog_ping();
  
  	return len;
  }
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
130
  static const struct watchdog_info ident = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
131
132
133
  	.options	= WDIOF_SETTIMEOUT,
  	.identity	= "Footbridge Watchdog",
  };
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
134
  static long watchdog_ioctl(struct file *file, unsigned int cmd,
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
135
  			   unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
137
  {
  	unsigned int new_margin;
edf86c9b9   Ben Dooks   [WATCHDOG] wdt285...
138
  	int __user *int_arg = (int __user *)arg;
795b89d20   Samuel Tardieu   [WATCHDOG] use EN...
139
  	int 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;
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
204
205
206
207
  	printk(KERN_INFO
  		"Footbridge Watchdog Timer: 0.01, timer margin: %d sec
  ",
  								soft_margin);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
208
209
  
  	if (machine_is_cats())
3f11df21a   Adrian Bunk   [WATCHDOG] fix wa...
210
  		printk(KERN_WARNING
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
211
212
  		  "Warning: Watchdog reset may not work on this machine.
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
213
214
215
216
217
218
219
220
221
222
223
224
225
226
  	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");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);
  
  module_param(soft_margin, int, 0);
d0e58eed0   Alan Cox   [WATCHDOG 55/57] ...
227
  MODULE_PARM_DESC(soft_margin, "Watchdog timeout in seconds");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
228
229
230
  
  module_init(footbridge_watchdog_init);
  module_exit(footbridge_watchdog_exit);