Blame view

drivers/watchdog/ixp4xx_wdt.c 4.65 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
  /*
f30c22695   Uwe Zeisberger   fix file specific...
2
   * drivers/char/watchdog/ixp4xx_wdt.c
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
3
4
5
6
7
8
9
10
11
12
13
14
   *
   * Watchdog driver for Intel IXP4xx network processors
   *
   * Author: Deepak Saxena <dsaxena@plexity.net>
   *
   * Copyright 2004 (c) MontaVista, Software, Inc.
   * Based on sa1100 driver, Copyright (C) 2000 Oleg Drokin <green@crimea.edu>
   *
   * This file is licensed under  the terms of the GNU General Public
   * License version 2. This program is licensed "as is" without any
   * warranty of any kind, whether express or implied.
   */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
  #include <linux/module.h>
  #include <linux/moduleparam.h>
  #include <linux/types.h>
  #include <linux/kernel.h>
  #include <linux/fs.h>
  #include <linux/miscdevice.h>
  #include <linux/watchdog.h>
  #include <linux/init.h>
  #include <linux/bitops.h>
089ab0791   Wim Van Sebroeck   [WATCHDOG] Clean-...
24
  #include <linux/uaccess.h>
a09e64fbc   Russell King   [ARM] Move includ...
25
  #include <mach/hardware.h>
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
26

4bfdf3783   Andrey Panin   [PATCH] consolida...
27
  static int nowayout = WATCHDOG_NOWAYOUT;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
28
29
30
  static int heartbeat = 60;	/* (secs) Default is 1 minute */
  static unsigned long wdt_status;
  static unsigned long boot_status;
9229376e9   Adrian Bunk   [WATCHDOG] fix wa...
31
  static DEFINE_SPINLOCK(wdt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
32
33
34
35
36
  
  #define WDT_TICK_RATE (IXP4XX_PERIPHERAL_BUS_CLOCK * 1000000UL)
  
  #define	WDT_IN_USE		0
  #define	WDT_OK_TO_CLOSE		1
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
37
  static void wdt_enable(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
38
  {
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
39
  	spin_lock(&wdt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
41
42
43
44
  	*IXP4XX_OSWK = IXP4XX_WDT_KEY;
  	*IXP4XX_OSWE = 0;
  	*IXP4XX_OSWT = WDT_TICK_RATE * heartbeat;
  	*IXP4XX_OSWE = IXP4XX_WDT_COUNT_ENABLE | IXP4XX_WDT_RESET_ENABLE;
  	*IXP4XX_OSWK = 0;
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
45
  	spin_unlock(&wdt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
46
  }
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
47
  static void wdt_disable(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
48
  {
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
49
  	spin_lock(&wdt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
50
51
52
  	*IXP4XX_OSWK = IXP4XX_WDT_KEY;
  	*IXP4XX_OSWE = 0;
  	*IXP4XX_OSWK = 0;
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
53
  	spin_unlock(&wdt_lock);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
54
  }
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
55
  static int ixp4xx_wdt_open(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
56
57
58
59
60
  {
  	if (test_and_set_bit(WDT_IN_USE, &wdt_status))
  		return -EBUSY;
  
  	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
61
  	wdt_enable();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
  	return nonseekable_open(inode, file);
  }
  
  static ssize_t
  ixp4xx_wdt_write(struct file *file, const char *data, size_t len, loff_t *ppos)
  {
  	if (len) {
  		if (!nowayout) {
  			size_t i;
  
  			clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  
  			for (i = 0; i != len; i++) {
  				char c;
  
  				if (get_user(c, data + i))
  					return -EFAULT;
  				if (c == 'V')
  					set_bit(WDT_OK_TO_CLOSE, &wdt_status);
  			}
  		}
  		wdt_enable();
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
85
86
  	return len;
  }
42747d712   Wim Van Sebroeck   [WATCHDOG] watchd...
87
  static const struct watchdog_info ident = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
88
89
90
91
  	.options	= WDIOF_CARDRESET | WDIOF_MAGICCLOSE |
  			  WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING,
  	.identity	= "IXP4xx Watchdog",
  };
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
92
93
  static long ixp4xx_wdt_ioctl(struct file *file, unsigned int cmd,
  							unsigned long arg)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
94
  {
795b89d20   Samuel Tardieu   [WATCHDOG] use EN...
95
  	int ret = -ENOTTY;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
  	int time;
  
  	switch (cmd) {
  	case WDIOC_GETSUPPORT:
  		ret = copy_to_user((struct watchdog_info *)arg, &ident,
  				   sizeof(ident)) ? -EFAULT : 0;
  		break;
  
  	case WDIOC_GETSTATUS:
  		ret = put_user(0, (int *)arg);
  		break;
  
  	case WDIOC_GETBOOTSTATUS:
  		ret = put_user(boot_status, (int *)arg);
  		break;
0c06090c9   Wim Van Sebroeck   [WATCHDOG] Coding...
111
112
113
114
  	case WDIOC_KEEPALIVE:
  		wdt_enable();
  		ret = 0;
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
  	case WDIOC_SETTIMEOUT:
  		ret = get_user(time, (int *)arg);
  		if (ret)
  			break;
  
  		if (time <= 0 || time > 60) {
  			ret = -EINVAL;
  			break;
  		}
  
  		heartbeat = time;
  		wdt_enable();
  		/* Fall through */
  
  	case WDIOC_GETTIMEOUT:
  		ret = put_user(heartbeat, (int *)arg);
  		break;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
132
133
134
  	}
  	return ret;
  }
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
135
  static int ixp4xx_wdt_release(struct inode *inode, struct file *file)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
136
  {
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
137
  	if (test_bit(WDT_OK_TO_CLOSE, &wdt_status))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
138
  		wdt_disable();
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
139
  	else
b36bbb6c3   Lennert Buytenhek   [PATCH] ixp4xx/ix...
140
  		printk(KERN_CRIT "WATCHDOG: Device closed unexpectedly - "
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
141
142
  					"timer will not stop
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
143
144
145
146
147
  	clear_bit(WDT_IN_USE, &wdt_status);
  	clear_bit(WDT_OK_TO_CLOSE, &wdt_status);
  
  	return 0;
  }
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
148
  static const struct file_operations ixp4xx_wdt_fops = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
149
150
151
  	.owner		= THIS_MODULE,
  	.llseek		= no_llseek,
  	.write		= ixp4xx_wdt_write,
20d35f3e5   Alan Cox   [WATCHDOG 22/57] ...
152
  	.unlocked_ioctl	= ixp4xx_wdt_ioctl,
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
153
154
155
  	.open		= ixp4xx_wdt_open,
  	.release	= ixp4xx_wdt_release,
  };
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
156
  static struct miscdevice ixp4xx_wdt_miscdev = {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
157
  	.minor		= WATCHDOG_MINOR,
2dab3cabc   Olaf Hering   [WATCHDOG] correc...
158
  	.name		= "watchdog",
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
159
160
161
162
163
164
  	.fops		= &ixp4xx_wdt_fops,
  };
  
  static int __init ixp4xx_wdt_init(void)
  {
  	int ret;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
165

0ba8b9b27   Russell King   [ARM] cputype: se...
166
  	if (!(read_cpuid_id() & 0xf) && !cpu_is_ixp46x()) {
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
167
168
169
  		printk(KERN_ERR "IXP4XXX Watchdog: Rev. A0 IXP42x CPU detected"
  			" - watchdog disabled
  ");
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
170
171
172
  
  		return -ENODEV;
  	}
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
173
174
  	boot_status = (*IXP4XX_OSST & IXP4XX_OSST_TIMER_WARM_RESET) ?
  			WDIOF_CARDRESET : 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
176
  	ret = misc_register(&ixp4xx_wdt_miscdev);
  	if (ret == 0)
7944d3a5a   Wim Van Sebroeck   [WATCHDOG] more c...
177
178
179
  		printk(KERN_INFO "IXP4xx Watchdog Timer: heartbeat %d sec
  ",
  			heartbeat);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  	return ret;
  }
  
  static void __exit ixp4xx_wdt_exit(void)
  {
  	misc_deregister(&ixp4xx_wdt_miscdev);
  }
  
  
  module_init(ixp4xx_wdt_init);
  module_exit(ixp4xx_wdt_exit);
  
  MODULE_AUTHOR("Deepak Saxena <dsaxena@plexity.net>");
  MODULE_DESCRIPTION("IXP4xx Network Processor Watchdog");
  
  module_param(heartbeat, int, 0);
  MODULE_PARM_DESC(heartbeat, "Watchdog heartbeat in seconds (default 60s)");
  
  module_param(nowayout, int, 0);
  MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started");
  
  MODULE_LICENSE("GPL");
  MODULE_ALIAS_MISCDEV(WATCHDOG_MINOR);