diff options
author | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-11 02:10:07 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2009-03-11 02:10:07 -0400 |
commit | e14eee56c2280953c6e3d24d5dce42bd90836b81 (patch) | |
tree | 21ab792d9ad6fbbab460058f352a0158f995644e /drivers/watchdog | |
parent | d6ee6f7e4c74d9a0fed7544f4d389bde004651d3 (diff) | |
parent | 99adcd9d67aaf04e28f5ae96df280f236bde4b66 (diff) |
Merge commit 'origin/master' into next
Diffstat (limited to 'drivers/watchdog')
-rw-r--r-- | drivers/watchdog/at91rm9200_wdt.c | 4 | ||||
-rw-r--r-- | drivers/watchdog/at91sam9_wdt.c | 1 | ||||
-rw-r--r-- | drivers/watchdog/gef_wdt.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/ks8695_wdt.c | 1 | ||||
-rw-r--r-- | drivers/watchdog/orion5x_wdt.c | 1 | ||||
-rw-r--r-- | drivers/watchdog/rc32434_wdt.c | 168 |
6 files changed, 75 insertions, 102 deletions
diff --git a/drivers/watchdog/at91rm9200_wdt.c b/drivers/watchdog/at91rm9200_wdt.c index 5531691f46ea..e35d54589232 100644 --- a/drivers/watchdog/at91rm9200_wdt.c +++ b/drivers/watchdog/at91rm9200_wdt.c | |||
@@ -107,10 +107,10 @@ static int at91_wdt_close(struct inode *inode, struct file *file) | |||
107 | static int at91_wdt_settimeout(int new_time) | 107 | static int at91_wdt_settimeout(int new_time) |
108 | { | 108 | { |
109 | /* | 109 | /* |
110 | * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz | 110 | * All counting occurs at SLOW_CLOCK / 128 = 256 Hz |
111 | * | 111 | * |
112 | * Since WDV is a 16-bit counter, the maximum period is | 112 | * Since WDV is a 16-bit counter, the maximum period is |
113 | * 65536 / 0.256 = 256 seconds. | 113 | * 65536 / 256 = 256 seconds. |
114 | */ | 114 | */ |
115 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) | 115 | if ((new_time <= 0) || (new_time > WDT_MAX_TIME)) |
116 | return -EINVAL; | 116 | return -EINVAL; |
diff --git a/drivers/watchdog/at91sam9_wdt.c b/drivers/watchdog/at91sam9_wdt.c index b1da287f90ec..a56ac84381b1 100644 --- a/drivers/watchdog/at91sam9_wdt.c +++ b/drivers/watchdog/at91sam9_wdt.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <linux/errno.h> | 18 | #include <linux/errno.h> |
19 | #include <linux/fs.h> | 19 | #include <linux/fs.h> |
20 | #include <linux/init.h> | 20 | #include <linux/init.h> |
21 | #include <linux/io.h> | ||
21 | #include <linux/kernel.h> | 22 | #include <linux/kernel.h> |
22 | #include <linux/miscdevice.h> | 23 | #include <linux/miscdevice.h> |
23 | #include <linux/module.h> | 24 | #include <linux/module.h> |
diff --git a/drivers/watchdog/gef_wdt.c b/drivers/watchdog/gef_wdt.c index f0c2b7a1a175..734d9806a872 100644 --- a/drivers/watchdog/gef_wdt.c +++ b/drivers/watchdog/gef_wdt.c | |||
@@ -269,7 +269,7 @@ static int __devinit gef_wdt_probe(struct of_device *dev, | |||
269 | bus_clk = 133; /* in MHz */ | 269 | bus_clk = 133; /* in MHz */ |
270 | 270 | ||
271 | freq = fsl_get_sys_freq(); | 271 | freq = fsl_get_sys_freq(); |
272 | if (freq > 0) | 272 | if (freq != -1) |
273 | bus_clk = freq; | 273 | bus_clk = freq; |
274 | 274 | ||
275 | /* Map devices registers into memory */ | 275 | /* Map devices registers into memory */ |
diff --git a/drivers/watchdog/ks8695_wdt.c b/drivers/watchdog/ks8695_wdt.c index 0b798fdaa378..74c92d384112 100644 --- a/drivers/watchdog/ks8695_wdt.c +++ b/drivers/watchdog/ks8695_wdt.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <linux/watchdog.h> | 21 | #include <linux/watchdog.h> |
22 | #include <linux/io.h> | 22 | #include <linux/io.h> |
23 | #include <linux/uaccess.h> | 23 | #include <linux/uaccess.h> |
24 | #include <mach/timex.h> | ||
24 | #include <mach/regs-timer.h> | 25 | #include <mach/regs-timer.h> |
25 | 26 | ||
26 | #define WDT_DEFAULT_TIME 5 /* seconds */ | 27 | #define WDT_DEFAULT_TIME 5 /* seconds */ |
diff --git a/drivers/watchdog/orion5x_wdt.c b/drivers/watchdog/orion5x_wdt.c index 14a339f58b6a..b64ae1a17832 100644 --- a/drivers/watchdog/orion5x_wdt.c +++ b/drivers/watchdog/orion5x_wdt.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #define WDT_EN 0x0010 | 29 | #define WDT_EN 0x0010 |
30 | #define WDT_VAL (TIMER_VIRT_BASE + 0x0024) | 30 | #define WDT_VAL (TIMER_VIRT_BASE + 0x0024) |
31 | 31 | ||
32 | #define ORION5X_TCLK 166666667 | ||
32 | #define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK) | 33 | #define WDT_MAX_DURATION (0xffffffff / ORION5X_TCLK) |
33 | #define WDT_IN_USE 0 | 34 | #define WDT_IN_USE 0 |
34 | #define WDT_OK_TO_CLOSE 1 | 35 | #define WDT_OK_TO_CLOSE 1 |
diff --git a/drivers/watchdog/rc32434_wdt.c b/drivers/watchdog/rc32434_wdt.c index 57027f4653ce..f3553fa40b17 100644 --- a/drivers/watchdog/rc32434_wdt.c +++ b/drivers/watchdog/rc32434_wdt.c | |||
@@ -34,104 +34,89 @@ | |||
34 | #include <asm/time.h> | 34 | #include <asm/time.h> |
35 | #include <asm/mach-rc32434/integ.h> | 35 | #include <asm/mach-rc32434/integ.h> |
36 | 36 | ||
37 | #define MAX_TIMEOUT 20 | 37 | #define VERSION "0.4" |
38 | #define RC32434_WDT_INTERVAL (15 * HZ) | ||
39 | |||
40 | #define VERSION "0.2" | ||
41 | 38 | ||
42 | static struct { | 39 | static struct { |
43 | struct completion stop; | ||
44 | int running; | ||
45 | struct timer_list timer; | ||
46 | int queue; | ||
47 | int default_ticks; | ||
48 | unsigned long inuse; | 40 | unsigned long inuse; |
49 | } rc32434_wdt_device; | 41 | } rc32434_wdt_device; |
50 | 42 | ||
51 | static struct integ __iomem *wdt_reg; | 43 | static struct integ __iomem *wdt_reg; |
52 | static int ticks = 100 * HZ; | ||
53 | 44 | ||
54 | static int expect_close; | 45 | static int expect_close; |
55 | static int timeout; | 46 | |
47 | /* Board internal clock speed in Hz, | ||
48 | * the watchdog timer ticks at. */ | ||
49 | extern unsigned int idt_cpu_freq; | ||
50 | |||
51 | /* translate wtcompare value to seconds and vice versa */ | ||
52 | #define WTCOMP2SEC(x) (x / idt_cpu_freq) | ||
53 | #define SEC2WTCOMP(x) (x * idt_cpu_freq) | ||
54 | |||
55 | /* Use a default timeout of 20s. This should be | ||
56 | * safe for CPU clock speeds up to 400MHz, as | ||
57 | * ((2 ^ 32) - 1) / (400MHz / 2) = 21s. */ | ||
58 | #define WATCHDOG_TIMEOUT 20 | ||
59 | |||
60 | static int timeout = WATCHDOG_TIMEOUT; | ||
56 | 61 | ||
57 | static int nowayout = WATCHDOG_NOWAYOUT; | 62 | static int nowayout = WATCHDOG_NOWAYOUT; |
58 | module_param(nowayout, int, 0); | 63 | module_param(nowayout, int, 0); |
59 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" | 64 | MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default=" |
60 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); | 65 | __MODULE_STRING(WATCHDOG_NOWAYOUT) ")"); |
61 | 66 | ||
67 | /* apply or and nand masks to data read from addr and write back */ | ||
68 | #define SET_BITS(addr, or, nand) \ | ||
69 | writel((readl(&addr) | or) & ~nand, &addr) | ||
62 | 70 | ||
63 | static void rc32434_wdt_start(void) | 71 | static void rc32434_wdt_start(void) |
64 | { | 72 | { |
65 | u32 val; | 73 | u32 or, nand; |
66 | |||
67 | if (!rc32434_wdt_device.inuse) { | ||
68 | writel(0, &wdt_reg->wtcount); | ||
69 | 74 | ||
70 | val = RC32434_ERR_WRE; | 75 | /* zero the counter before enabling */ |
71 | writel(readl(&wdt_reg->errcs) | val, &wdt_reg->errcs); | 76 | writel(0, &wdt_reg->wtcount); |
72 | 77 | ||
73 | val = RC32434_WTC_EN; | 78 | /* don't generate a non-maskable interrupt, |
74 | writel(readl(&wdt_reg->wtc) | val, &wdt_reg->wtc); | 79 | * do a warm reset instead */ |
75 | } | 80 | nand = 1 << RC32434_ERR_WNE; |
76 | rc32434_wdt_device.running++; | 81 | or = 1 << RC32434_ERR_WRE; |
77 | } | ||
78 | 82 | ||
79 | static void rc32434_wdt_stop(void) | 83 | /* reset the ERRCS timeout bit in case it's set */ |
80 | { | 84 | nand |= 1 << RC32434_ERR_WTO; |
81 | u32 val; | ||
82 | 85 | ||
83 | if (rc32434_wdt_device.running) { | 86 | SET_BITS(wdt_reg->errcs, or, nand); |
84 | 87 | ||
85 | val = ~RC32434_WTC_EN; | 88 | /* reset WTC timeout bit and enable WDT */ |
86 | writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc); | 89 | nand = 1 << RC32434_WTC_TO; |
90 | or = 1 << RC32434_WTC_EN; | ||
87 | 91 | ||
88 | val = ~RC32434_ERR_WRE; | 92 | SET_BITS(wdt_reg->wtc, or, nand); |
89 | writel(readl(&wdt_reg->errcs) & val, &wdt_reg->errcs); | 93 | } |
90 | 94 | ||
91 | rc32434_wdt_device.running = 0; | 95 | static void rc32434_wdt_stop(void) |
92 | } | 96 | { |
97 | /* Disable WDT */ | ||
98 | SET_BITS(wdt_reg->wtc, 0, 1 << RC32434_WTC_EN); | ||
93 | } | 99 | } |
94 | 100 | ||
95 | static void rc32434_wdt_set(int new_timeout) | 101 | static int rc32434_wdt_set(int new_timeout) |
96 | { | 102 | { |
97 | u32 cmp = new_timeout * HZ; | 103 | int max_to = WTCOMP2SEC((u32)-1); |
98 | u32 state, val; | ||
99 | 104 | ||
105 | if (new_timeout < 0 || new_timeout > max_to) { | ||
106 | printk(KERN_ERR KBUILD_MODNAME | ||
107 | ": timeout value must be between 0 and %d", | ||
108 | max_to); | ||
109 | return -EINVAL; | ||
110 | } | ||
100 | timeout = new_timeout; | 111 | timeout = new_timeout; |
101 | /* | 112 | writel(SEC2WTCOMP(timeout), &wdt_reg->wtcompare); |
102 | * store and disable WTC | ||
103 | */ | ||
104 | state = (u32)(readl(&wdt_reg->wtc) & RC32434_WTC_EN); | ||
105 | val = ~RC32434_WTC_EN; | ||
106 | writel(readl(&wdt_reg->wtc) & val, &wdt_reg->wtc); | ||
107 | |||
108 | writel(0, &wdt_reg->wtcount); | ||
109 | writel(cmp, &wdt_reg->wtcompare); | ||
110 | |||
111 | /* | ||
112 | * restore WTC | ||
113 | */ | ||
114 | |||
115 | writel(readl(&wdt_reg->wtc) | state, &wdt_reg); | ||
116 | } | ||
117 | 113 | ||
118 | static void rc32434_wdt_reset(void) | 114 | return 0; |
119 | { | ||
120 | ticks = rc32434_wdt_device.default_ticks; | ||
121 | } | 115 | } |
122 | 116 | ||
123 | static void rc32434_wdt_update(unsigned long unused) | 117 | static void rc32434_wdt_ping(void) |
124 | { | 118 | { |
125 | if (rc32434_wdt_device.running) | ||
126 | ticks--; | ||
127 | |||
128 | writel(0, &wdt_reg->wtcount); | 119 | writel(0, &wdt_reg->wtcount); |
129 | |||
130 | if (rc32434_wdt_device.queue && ticks) | ||
131 | mod_timer(&rc32434_wdt_device.timer, | ||
132 | jiffies + RC32434_WDT_INTERVAL); | ||
133 | else | ||
134 | complete(&rc32434_wdt_device.stop); | ||
135 | } | 120 | } |
136 | 121 | ||
137 | static int rc32434_wdt_open(struct inode *inode, struct file *file) | 122 | static int rc32434_wdt_open(struct inode *inode, struct file *file) |
@@ -142,19 +127,23 @@ static int rc32434_wdt_open(struct inode *inode, struct file *file) | |||
142 | if (nowayout) | 127 | if (nowayout) |
143 | __module_get(THIS_MODULE); | 128 | __module_get(THIS_MODULE); |
144 | 129 | ||
130 | rc32434_wdt_start(); | ||
131 | rc32434_wdt_ping(); | ||
132 | |||
145 | return nonseekable_open(inode, file); | 133 | return nonseekable_open(inode, file); |
146 | } | 134 | } |
147 | 135 | ||
148 | static int rc32434_wdt_release(struct inode *inode, struct file *file) | 136 | static int rc32434_wdt_release(struct inode *inode, struct file *file) |
149 | { | 137 | { |
150 | if (expect_close && nowayout == 0) { | 138 | if (expect_close == 42) { |
151 | rc32434_wdt_stop(); | 139 | rc32434_wdt_stop(); |
152 | printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n"); | 140 | printk(KERN_INFO KBUILD_MODNAME ": disabling watchdog timer\n"); |
153 | module_put(THIS_MODULE); | 141 | module_put(THIS_MODULE); |
154 | } else | 142 | } else { |
155 | printk(KERN_CRIT KBUILD_MODNAME | 143 | printk(KERN_CRIT KBUILD_MODNAME |
156 | ": device closed unexpectedly. WDT will not stop !\n"); | 144 | ": device closed unexpectedly. WDT will not stop !\n"); |
157 | 145 | rc32434_wdt_ping(); | |
146 | } | ||
158 | clear_bit(0, &rc32434_wdt_device.inuse); | 147 | clear_bit(0, &rc32434_wdt_device.inuse); |
159 | return 0; | 148 | return 0; |
160 | } | 149 | } |
@@ -174,10 +163,10 @@ static ssize_t rc32434_wdt_write(struct file *file, const char *data, | |||
174 | if (get_user(c, data + i)) | 163 | if (get_user(c, data + i)) |
175 | return -EFAULT; | 164 | return -EFAULT; |
176 | if (c == 'V') | 165 | if (c == 'V') |
177 | expect_close = 1; | 166 | expect_close = 42; |
178 | } | 167 | } |
179 | } | 168 | } |
180 | rc32434_wdt_update(0); | 169 | rc32434_wdt_ping(); |
181 | return len; | 170 | return len; |
182 | } | 171 | } |
183 | return 0; | 172 | return 0; |
@@ -197,11 +186,11 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd, | |||
197 | }; | 186 | }; |
198 | switch (cmd) { | 187 | switch (cmd) { |
199 | case WDIOC_KEEPALIVE: | 188 | case WDIOC_KEEPALIVE: |
200 | rc32434_wdt_reset(); | 189 | rc32434_wdt_ping(); |
201 | break; | 190 | break; |
202 | case WDIOC_GETSTATUS: | 191 | case WDIOC_GETSTATUS: |
203 | case WDIOC_GETBOOTSTATUS: | 192 | case WDIOC_GETBOOTSTATUS: |
204 | value = readl(&wdt_reg->wtcount); | 193 | value = 0; |
205 | if (copy_to_user(argp, &value, sizeof(int))) | 194 | if (copy_to_user(argp, &value, sizeof(int))) |
206 | return -EFAULT; | 195 | return -EFAULT; |
207 | break; | 196 | break; |
@@ -218,6 +207,7 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd, | |||
218 | break; | 207 | break; |
219 | case WDIOS_DISABLECARD: | 208 | case WDIOS_DISABLECARD: |
220 | rc32434_wdt_stop(); | 209 | rc32434_wdt_stop(); |
210 | break; | ||
221 | default: | 211 | default: |
222 | return -EINVAL; | 212 | return -EINVAL; |
223 | } | 213 | } |
@@ -225,11 +215,9 @@ static long rc32434_wdt_ioctl(struct file *file, unsigned int cmd, | |||
225 | case WDIOC_SETTIMEOUT: | 215 | case WDIOC_SETTIMEOUT: |
226 | if (copy_from_user(&new_timeout, argp, sizeof(int))) | 216 | if (copy_from_user(&new_timeout, argp, sizeof(int))) |
227 | return -EFAULT; | 217 | return -EFAULT; |
228 | if (new_timeout < 1) | 218 | if (rc32434_wdt_set(new_timeout)) |
229 | return -EINVAL; | 219 | return -EINVAL; |
230 | if (new_timeout > MAX_TIMEOUT) | 220 | /* Fall through */ |
231 | return -EINVAL; | ||
232 | rc32434_wdt_set(new_timeout); | ||
233 | case WDIOC_GETTIMEOUT: | 221 | case WDIOC_GETTIMEOUT: |
234 | return copy_to_user(argp, &timeout, sizeof(int)); | 222 | return copy_to_user(argp, &timeout, sizeof(int)); |
235 | default: | 223 | default: |
@@ -254,15 +242,15 @@ static struct miscdevice rc32434_wdt_miscdev = { | |||
254 | .fops = &rc32434_wdt_fops, | 242 | .fops = &rc32434_wdt_fops, |
255 | }; | 243 | }; |
256 | 244 | ||
257 | static char banner[] = KERN_INFO KBUILD_MODNAME | 245 | static char banner[] __devinitdata = KERN_INFO KBUILD_MODNAME |
258 | ": Watchdog Timer version " VERSION ", timer margin: %d sec\n"; | 246 | ": Watchdog Timer version " VERSION ", timer margin: %d sec\n"; |
259 | 247 | ||
260 | static int rc32434_wdt_probe(struct platform_device *pdev) | 248 | static int __devinit rc32434_wdt_probe(struct platform_device *pdev) |
261 | { | 249 | { |
262 | int ret; | 250 | int ret; |
263 | struct resource *r; | 251 | struct resource *r; |
264 | 252 | ||
265 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb500_wdt_res"); | 253 | r = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rb532_wdt_res"); |
266 | if (!r) { | 254 | if (!r) { |
267 | printk(KERN_ERR KBUILD_MODNAME | 255 | printk(KERN_ERR KBUILD_MODNAME |
268 | "failed to retrieve resources\n"); | 256 | "failed to retrieve resources\n"); |
@@ -277,24 +265,12 @@ static int rc32434_wdt_probe(struct platform_device *pdev) | |||
277 | } | 265 | } |
278 | 266 | ||
279 | ret = misc_register(&rc32434_wdt_miscdev); | 267 | ret = misc_register(&rc32434_wdt_miscdev); |
280 | |||
281 | if (ret < 0) { | 268 | if (ret < 0) { |
282 | printk(KERN_ERR KBUILD_MODNAME | 269 | printk(KERN_ERR KBUILD_MODNAME |
283 | "failed to register watchdog device\n"); | 270 | "failed to register watchdog device\n"); |
284 | goto unmap; | 271 | goto unmap; |
285 | } | 272 | } |
286 | 273 | ||
287 | init_completion(&rc32434_wdt_device.stop); | ||
288 | rc32434_wdt_device.queue = 0; | ||
289 | |||
290 | clear_bit(0, &rc32434_wdt_device.inuse); | ||
291 | |||
292 | setup_timer(&rc32434_wdt_device.timer, rc32434_wdt_update, 0L); | ||
293 | |||
294 | rc32434_wdt_device.default_ticks = ticks; | ||
295 | |||
296 | rc32434_wdt_start(); | ||
297 | |||
298 | printk(banner, timeout); | 274 | printk(banner, timeout); |
299 | 275 | ||
300 | return 0; | 276 | return 0; |
@@ -304,23 +280,17 @@ unmap: | |||
304 | return ret; | 280 | return ret; |
305 | } | 281 | } |
306 | 282 | ||
307 | static int rc32434_wdt_remove(struct platform_device *pdev) | 283 | static int __devexit rc32434_wdt_remove(struct platform_device *pdev) |
308 | { | 284 | { |
309 | if (rc32434_wdt_device.queue) { | ||
310 | rc32434_wdt_device.queue = 0; | ||
311 | wait_for_completion(&rc32434_wdt_device.stop); | ||
312 | } | ||
313 | misc_deregister(&rc32434_wdt_miscdev); | 285 | misc_deregister(&rc32434_wdt_miscdev); |
314 | |||
315 | iounmap(wdt_reg); | 286 | iounmap(wdt_reg); |
316 | |||
317 | return 0; | 287 | return 0; |
318 | } | 288 | } |
319 | 289 | ||
320 | static struct platform_driver rc32434_wdt = { | 290 | static struct platform_driver rc32434_wdt = { |
321 | .probe = rc32434_wdt_probe, | 291 | .probe = rc32434_wdt_probe, |
322 | .remove = rc32434_wdt_remove, | 292 | .remove = __devexit_p(rc32434_wdt_remove), |
323 | .driver = { | 293 | .driver = { |
324 | .name = "rc32434_wdt", | 294 | .name = "rc32434_wdt", |
325 | } | 295 | } |
326 | }; | 296 | }; |