Commit 1950f499df4eacb5d89cf0151f5edda139b800f4
1 parent
4096812636
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
watchdog: shwdt: Conversion to watchdog core.
Fairly straightforward conversion to utilize watchdog core support. Signed-off-by: Paul Mundt <lethal@linux-sh.org>
Showing 2 changed files with 45 additions and 154 deletions Side-by-side Diff
drivers/watchdog/Kconfig
... | ... | @@ -1138,6 +1138,7 @@ |
1138 | 1138 | config SH_WDT |
1139 | 1139 | tristate "SuperH Watchdog" |
1140 | 1140 | depends on SUPERH && (CPU_SH3 || CPU_SH4) |
1141 | + select WATCHDOG_CORE | |
1141 | 1142 | help |
1142 | 1143 | This driver adds watchdog support for the integrated watchdog in the |
1143 | 1144 | SuperH processors. If you have one of these processors and wish |
drivers/watchdog/shwdt.c
... | ... | @@ -27,12 +27,10 @@ |
27 | 27 | #include <linux/types.h> |
28 | 28 | #include <linux/miscdevice.h> |
29 | 29 | #include <linux/watchdog.h> |
30 | -#include <linux/ioport.h> | |
31 | 30 | #include <linux/fs.h> |
32 | 31 | #include <linux/mm.h> |
33 | 32 | #include <linux/slab.h> |
34 | 33 | #include <linux/io.h> |
35 | -#include <linux/uaccess.h> | |
36 | 34 | #include <asm/watchdog.h> |
37 | 35 | |
38 | 36 | #define DRV_NAME "sh-wdt" |
... | ... | @@ -67,8 +65,6 @@ |
67 | 65 | static int clock_division_ratio = WTCSR_CKS_4096; |
68 | 66 | #define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) |
69 | 67 | |
70 | -static const struct watchdog_info sh_wdt_info; | |
71 | -static struct platform_device *sh_wdt_dev; | |
72 | 68 | static DEFINE_SPINLOCK(shwdt_lock); |
73 | 69 | |
74 | 70 | #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ |
75 | 71 | |
... | ... | @@ -86,8 +82,9 @@ |
86 | 82 | char expect_close; |
87 | 83 | }; |
88 | 84 | |
89 | -static void sh_wdt_start(struct sh_wdt *wdt) | |
85 | +static int sh_wdt_start(struct watchdog_device *wdt_dev) | |
90 | 86 | { |
87 | + struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev); | |
91 | 88 | unsigned long flags; |
92 | 89 | u8 csr; |
93 | 90 | |
94 | 91 | |
95 | 92 | |
... | ... | @@ -121,10 +118,13 @@ |
121 | 118 | sh_wdt_write_rstcsr(csr); |
122 | 119 | #endif |
123 | 120 | spin_unlock_irqrestore(&shwdt_lock, flags); |
121 | + | |
122 | + return 0; | |
124 | 123 | } |
125 | 124 | |
126 | -static void sh_wdt_stop(struct sh_wdt *wdt) | |
125 | +static int sh_wdt_stop(struct watchdog_device *wdt_dev) | |
127 | 126 | { |
127 | + struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev); | |
128 | 128 | unsigned long flags; |
129 | 129 | u8 csr; |
130 | 130 | |
131 | 131 | |
132 | 132 | |
133 | 133 | |
... | ... | @@ -137,18 +137,22 @@ |
137 | 137 | sh_wdt_write_csr(csr); |
138 | 138 | |
139 | 139 | spin_unlock_irqrestore(&shwdt_lock, flags); |
140 | + | |
141 | + return 0; | |
140 | 142 | } |
141 | 143 | |
142 | -static inline void sh_wdt_keepalive(struct sh_wdt *wdt) | |
144 | +static int sh_wdt_keepalive(struct watchdog_device *wdt_dev) | |
143 | 145 | { |
144 | 146 | unsigned long flags; |
145 | 147 | |
146 | 148 | spin_lock_irqsave(&shwdt_lock, flags); |
147 | 149 | next_heartbeat = jiffies + (heartbeat * HZ); |
148 | 150 | spin_unlock_irqrestore(&shwdt_lock, flags); |
151 | + | |
152 | + return 0; | |
149 | 153 | } |
150 | 154 | |
151 | -static int sh_wdt_set_heartbeat(int t) | |
155 | +static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t) | |
152 | 156 | { |
153 | 157 | unsigned long flags; |
154 | 158 | |
155 | 159 | |
... | ... | @@ -157,7 +161,9 @@ |
157 | 161 | |
158 | 162 | spin_lock_irqsave(&shwdt_lock, flags); |
159 | 163 | heartbeat = t; |
164 | + wdt_dev->timeout = t; | |
160 | 165 | spin_unlock_irqrestore(&shwdt_lock, flags); |
166 | + | |
161 | 167 | return 0; |
162 | 168 | } |
163 | 169 | |
... | ... | @@ -183,123 +189,6 @@ |
183 | 189 | spin_unlock_irqrestore(&shwdt_lock, flags); |
184 | 190 | } |
185 | 191 | |
186 | -static int sh_wdt_open(struct inode *inode, struct file *file) | |
187 | -{ | |
188 | - struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev); | |
189 | - | |
190 | - if (test_and_set_bit(0, &wdt->enabled)) | |
191 | - return -EBUSY; | |
192 | - if (nowayout) | |
193 | - __module_get(THIS_MODULE); | |
194 | - | |
195 | - file->private_data = wdt; | |
196 | - | |
197 | - sh_wdt_start(wdt); | |
198 | - | |
199 | - return nonseekable_open(inode, file); | |
200 | -} | |
201 | - | |
202 | -static int sh_wdt_close(struct inode *inode, struct file *file) | |
203 | -{ | |
204 | - struct sh_wdt *wdt = file->private_data; | |
205 | - | |
206 | - if (wdt->expect_close == 42) { | |
207 | - sh_wdt_stop(wdt); | |
208 | - } else { | |
209 | - dev_crit(wdt->dev, "Unexpected close, not " | |
210 | - "stopping watchdog!\n"); | |
211 | - sh_wdt_keepalive(wdt); | |
212 | - } | |
213 | - | |
214 | - clear_bit(0, &wdt->enabled); | |
215 | - wdt->expect_close = 0; | |
216 | - | |
217 | - return 0; | |
218 | -} | |
219 | - | |
220 | -static ssize_t sh_wdt_write(struct file *file, const char *buf, | |
221 | - size_t count, loff_t *ppos) | |
222 | -{ | |
223 | - struct sh_wdt *wdt = file->private_data; | |
224 | - | |
225 | - if (count) { | |
226 | - if (!nowayout) { | |
227 | - size_t i; | |
228 | - | |
229 | - wdt->expect_close = 0; | |
230 | - | |
231 | - for (i = 0; i != count; i++) { | |
232 | - char c; | |
233 | - if (get_user(c, buf + i)) | |
234 | - return -EFAULT; | |
235 | - if (c == 'V') | |
236 | - wdt->expect_close = 42; | |
237 | - } | |
238 | - } | |
239 | - sh_wdt_keepalive(wdt); | |
240 | - } | |
241 | - | |
242 | - return count; | |
243 | -} | |
244 | - | |
245 | -static long sh_wdt_ioctl(struct file *file, unsigned int cmd, | |
246 | - unsigned long arg) | |
247 | -{ | |
248 | - struct sh_wdt *wdt = file->private_data; | |
249 | - int new_heartbeat; | |
250 | - int options, retval = -EINVAL; | |
251 | - | |
252 | - switch (cmd) { | |
253 | - case WDIOC_GETSUPPORT: | |
254 | - return copy_to_user((struct watchdog_info *)arg, | |
255 | - &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0; | |
256 | - case WDIOC_GETSTATUS: | |
257 | - case WDIOC_GETBOOTSTATUS: | |
258 | - return put_user(0, (int *)arg); | |
259 | - case WDIOC_SETOPTIONS: | |
260 | - if (get_user(options, (int *)arg)) | |
261 | - return -EFAULT; | |
262 | - | |
263 | - if (options & WDIOS_DISABLECARD) { | |
264 | - sh_wdt_stop(wdt); | |
265 | - retval = 0; | |
266 | - } | |
267 | - | |
268 | - if (options & WDIOS_ENABLECARD) { | |
269 | - sh_wdt_start(wdt); | |
270 | - retval = 0; | |
271 | - } | |
272 | - | |
273 | - return retval; | |
274 | - case WDIOC_KEEPALIVE: | |
275 | - sh_wdt_keepalive(wdt); | |
276 | - return 0; | |
277 | - case WDIOC_SETTIMEOUT: | |
278 | - if (get_user(new_heartbeat, (int *)arg)) | |
279 | - return -EFAULT; | |
280 | - | |
281 | - if (sh_wdt_set_heartbeat(new_heartbeat)) | |
282 | - return -EINVAL; | |
283 | - | |
284 | - sh_wdt_keepalive(wdt); | |
285 | - /* Fall */ | |
286 | - case WDIOC_GETTIMEOUT: | |
287 | - return put_user(heartbeat, (int *)arg); | |
288 | - default: | |
289 | - return -ENOTTY; | |
290 | - } | |
291 | - return 0; | |
292 | -} | |
293 | - | |
294 | -static const struct file_operations sh_wdt_fops = { | |
295 | - .owner = THIS_MODULE, | |
296 | - .llseek = no_llseek, | |
297 | - .write = sh_wdt_write, | |
298 | - .unlocked_ioctl = sh_wdt_ioctl, | |
299 | - .open = sh_wdt_open, | |
300 | - .release = sh_wdt_close, | |
301 | -}; | |
302 | - | |
303 | 192 | static const struct watchdog_info sh_wdt_info = { |
304 | 193 | .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | |
305 | 194 | WDIOF_MAGICCLOSE, |
306 | 195 | |
... | ... | @@ -307,12 +196,19 @@ |
307 | 196 | .identity = "SH WDT", |
308 | 197 | }; |
309 | 198 | |
310 | -static struct miscdevice sh_wdt_miscdev = { | |
311 | - .minor = WATCHDOG_MINOR, | |
312 | - .name = "watchdog", | |
313 | - .fops = &sh_wdt_fops, | |
199 | +static const struct watchdog_ops sh_wdt_ops = { | |
200 | + .owner = THIS_MODULE, | |
201 | + .start = sh_wdt_start, | |
202 | + .stop = sh_wdt_stop, | |
203 | + .ping = sh_wdt_keepalive, | |
204 | + .set_timeout = sh_wdt_set_heartbeat, | |
314 | 205 | }; |
315 | 206 | |
207 | +static struct watchdog_device sh_wdt_dev = { | |
208 | + .info = &sh_wdt_info, | |
209 | + .ops = &sh_wdt_ops, | |
210 | +}; | |
211 | + | |
316 | 212 | static int __devinit sh_wdt_probe(struct platform_device *pdev) |
317 | 213 | { |
318 | 214 | struct sh_wdt *wdt; |
319 | 215 | |
320 | 216 | |
... | ... | @@ -348,13 +244,25 @@ |
348 | 244 | goto out_err; |
349 | 245 | } |
350 | 246 | |
351 | - sh_wdt_miscdev.parent = wdt->dev; | |
247 | + rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat); | |
248 | + if (unlikely(rc)) { | |
249 | + /* Default timeout if invalid */ | |
250 | + sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT); | |
352 | 251 | |
353 | - rc = misc_register(&sh_wdt_miscdev); | |
252 | + dev_warn(&pdev->dev, | |
253 | + "heartbeat value must be 1<=x<=3600, using %d\n", | |
254 | + sh_wdt_dev.timeout); | |
255 | + } | |
256 | + | |
257 | + dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n", | |
258 | + sh_wdt_dev.timeout, nowayout); | |
259 | + | |
260 | + watchdog_set_nowayout(&sh_wdt_dev, nowayout); | |
261 | + watchdog_set_drvdata(&sh_wdt_dev, wdt); | |
262 | + | |
263 | + rc = watchdog_register_device(&sh_wdt_dev); | |
354 | 264 | if (unlikely(rc)) { |
355 | - dev_err(&pdev->dev, | |
356 | - "Can't register miscdev on minor=%d (err=%d)\n", | |
357 | - sh_wdt_miscdev.minor, rc); | |
265 | + dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc); | |
358 | 266 | goto out_unmap; |
359 | 267 | } |
360 | 268 | |
... | ... | @@ -364,7 +272,6 @@ |
364 | 272 | wdt->timer.expires = next_ping_period(clock_division_ratio); |
365 | 273 | |
366 | 274 | platform_set_drvdata(pdev, wdt); |
367 | - sh_wdt_dev = pdev; | |
368 | 275 | |
369 | 276 | dev_info(&pdev->dev, "initialized.\n"); |
370 | 277 | |
371 | 278 | |
... | ... | @@ -387,10 +294,8 @@ |
387 | 294 | |
388 | 295 | platform_set_drvdata(pdev, NULL); |
389 | 296 | |
390 | - misc_deregister(&sh_wdt_miscdev); | |
297 | + watchdog_unregister_device(&sh_wdt_dev); | |
391 | 298 | |
392 | - sh_wdt_dev = NULL; | |
393 | - | |
394 | 299 | devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); |
395 | 300 | devm_iounmap(&pdev->dev, wdt->base); |
396 | 301 | devm_kfree(&pdev->dev, wdt); |
... | ... | @@ -400,9 +305,7 @@ |
400 | 305 | |
401 | 306 | static void sh_wdt_shutdown(struct platform_device *pdev) |
402 | 307 | { |
403 | - struct sh_wdt *wdt = platform_get_drvdata(pdev); | |
404 | - | |
405 | - sh_wdt_stop(wdt); | |
308 | + sh_wdt_stop(&sh_wdt_dev); | |
406 | 309 | } |
407 | 310 | |
408 | 311 | static struct platform_driver sh_wdt_driver = { |
... | ... | @@ -418,8 +321,6 @@ |
418 | 321 | |
419 | 322 | static int __init sh_wdt_init(void) |
420 | 323 | { |
421 | - int rc; | |
422 | - | |
423 | 324 | if (unlikely(clock_division_ratio < 0x5 || |
424 | 325 | clock_division_ratio > 0x7)) { |
425 | 326 | clock_division_ratio = WTCSR_CKS_4096; |
... | ... | @@ -427,17 +328,6 @@ |
427 | 328 | pr_info("divisor must be 0x5<=x<=0x7, using %d\n", |
428 | 329 | clock_division_ratio); |
429 | 330 | } |
430 | - | |
431 | - rc = sh_wdt_set_heartbeat(heartbeat); | |
432 | - if (unlikely(rc)) { | |
433 | - heartbeat = WATCHDOG_HEARTBEAT; | |
434 | - | |
435 | - pr_info("heartbeat value must be 1<=x<=3600, using %d\n", | |
436 | - heartbeat); | |
437 | - } | |
438 | - | |
439 | - pr_info("configured with heartbeat=%d sec (nowayout=%d)\n", | |
440 | - heartbeat, nowayout); | |
441 | 331 | |
442 | 332 | return platform_driver_register(&sh_wdt_driver); |
443 | 333 | } |