Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

watchdog: w83627hf: Convert to watchdog infrastructure

Signed-off-by: Guenter Roeck <linux@roeck-us.net>
Signed-off-by: Wim Van Sebroeck <wim@iguana.be>

authored by

Guenter Roeck and committed by
Wim Van Sebroeck
30a83695 4a7e94a0

+53 -173
+1
drivers/watchdog/Kconfig
··· 885 885 config W83627HF_WDT 886 886 tristate "W83627HF/W83627DHG Watchdog Timer" 887 887 depends on X86 888 + select WATCHDOG_CORE 888 889 ---help--- 889 890 This is the driver for the hardware watchdog on the W83627HF chipset 890 891 as used in Advantech PC-9578 and Tyan S2721-533 motherboards
+52 -173
drivers/watchdog/w83627hf_wdt.c
··· 1 1 /* 2 2 * w83627hf/thf WDT driver 3 3 * 4 + * (c) Copyright 2013 Guenter Roeck 5 + * converted to watchdog infrastructure 6 + * 4 7 * (c) Copyright 2007 Vlad Drukker <vlad@storewiz.com> 5 8 * added support for W83627THF. 6 9 * ··· 34 31 #include <linux/module.h> 35 32 #include <linux/moduleparam.h> 36 33 #include <linux/types.h> 37 - #include <linux/miscdevice.h> 38 34 #include <linux/watchdog.h> 39 - #include <linux/fs.h> 40 35 #include <linux/ioport.h> 41 36 #include <linux/notifier.h> 42 37 #include <linux/reboot.h> 43 38 #include <linux/init.h> 44 - #include <linux/spinlock.h> 45 39 #include <linux/io.h> 46 - #include <linux/uaccess.h> 47 - 48 40 49 41 #define WATCHDOG_NAME "w83627hf/thf/hg/dhg WDT" 50 42 #define WATCHDOG_TIMEOUT 60 /* 60 sec default timeout */ 51 - 52 - static unsigned long wdt_is_open; 53 - static char expect_close; 54 - static DEFINE_SPINLOCK(io_lock); 55 43 56 44 /* You must set this - there is no sane way to probe for this board. */ 57 45 static int wdt_io = 0x2E; 58 46 module_param(wdt_io, int, 0); 59 47 MODULE_PARM_DESC(wdt_io, "w83627hf/thf WDT io port (default 0x2E)"); 60 48 61 - static int timeout = WATCHDOG_TIMEOUT; /* in seconds */ 49 + static int timeout; /* in seconds */ 62 50 module_param(timeout, int, 0); 63 51 MODULE_PARM_DESC(timeout, 64 52 "Watchdog timeout in seconds. 1 <= timeout <= 255, default=" ··· 104 110 /* tyan motherboards seem to set F5 to 0x4C ? 105 111 * So explicitly init to appropriate value. */ 106 112 107 - static void w83627hf_init(void) 113 + static void w83627hf_init(struct watchdog_device *wdog) 108 114 { 109 115 unsigned char t; 110 116 ··· 114 120 t = inb_p(WDT_EFDR); /* read CRF6 */ 115 121 if (t != 0) { 116 122 pr_info("Watchdog already running. Resetting timeout to %d sec\n", 117 - timeout); 118 - outb_p(timeout, WDT_EFDR); /* Write back to CRF6 */ 123 + wdog->timeout); 124 + outb_p(wdog->timeout, WDT_EFDR); /* Write back to CRF6 */ 119 125 } 120 126 121 127 outb_p(0xF5, WDT_EFER); /* Select CRF5 */ ··· 135 141 w83627hf_unselect_wd_register(); 136 142 } 137 143 138 - static void wdt_set_time(int timeout) 144 + static int wdt_set_time(unsigned int timeout) 139 145 { 140 - spin_lock(&io_lock); 141 - 142 146 w83627hf_select_wd_register(); 143 147 144 148 outb_p(0xF6, WDT_EFER); /* Select CRF6 */ ··· 144 152 145 153 w83627hf_unselect_wd_register(); 146 154 147 - spin_unlock(&io_lock); 148 - } 149 - 150 - static int wdt_ping(void) 151 - { 152 - wdt_set_time(timeout); 153 155 return 0; 154 156 } 155 157 156 - static int wdt_disable(void) 158 + static int wdt_start(struct watchdog_device *wdog) 157 159 { 158 - wdt_set_time(0); 160 + return wdt_set_time(wdog->timeout); 161 + } 162 + 163 + static int wdt_stop(struct watchdog_device *wdog) 164 + { 165 + return wdt_set_time(0); 166 + } 167 + 168 + static int wdt_set_timeout(struct watchdog_device *wdog, unsigned int timeout) 169 + { 170 + wdog->timeout = timeout; 171 + 159 172 return 0; 160 173 } 161 174 162 - static int wdt_set_heartbeat(int t) 175 + static unsigned int wdt_get_time(struct watchdog_device *wdog) 163 176 { 164 - if (t < 1 || t > 255) 165 - return -EINVAL; 166 - timeout = t; 167 - return 0; 168 - } 169 - 170 - static int wdt_get_time(void) 171 - { 172 - int timeleft; 173 - 174 - spin_lock(&io_lock); 177 + unsigned int timeleft; 175 178 176 179 w83627hf_select_wd_register(); 177 180 ··· 175 188 176 189 w83627hf_unselect_wd_register(); 177 190 178 - spin_unlock(&io_lock); 179 - 180 191 return timeleft; 181 - } 182 - 183 - static ssize_t wdt_write(struct file *file, const char __user *buf, 184 - size_t count, loff_t *ppos) 185 - { 186 - if (count) { 187 - if (!nowayout) { 188 - size_t i; 189 - 190 - expect_close = 0; 191 - 192 - for (i = 0; i != count; i++) { 193 - char c; 194 - if (get_user(c, buf + i)) 195 - return -EFAULT; 196 - if (c == 'V') 197 - expect_close = 42; 198 - } 199 - } 200 - wdt_ping(); 201 - } 202 - return count; 203 - } 204 - 205 - static long wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) 206 - { 207 - void __user *argp = (void __user *)arg; 208 - int __user *p = argp; 209 - int timeval; 210 - static const struct watchdog_info ident = { 211 - .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | 212 - WDIOF_MAGICCLOSE, 213 - .firmware_version = 1, 214 - .identity = "W83627HF WDT", 215 - }; 216 - 217 - switch (cmd) { 218 - case WDIOC_GETSUPPORT: 219 - if (copy_to_user(argp, &ident, sizeof(ident))) 220 - return -EFAULT; 221 - break; 222 - case WDIOC_GETSTATUS: 223 - case WDIOC_GETBOOTSTATUS: 224 - return put_user(0, p); 225 - case WDIOC_SETOPTIONS: 226 - { 227 - int options, retval = -EINVAL; 228 - 229 - if (get_user(options, p)) 230 - return -EFAULT; 231 - if (options & WDIOS_DISABLECARD) { 232 - wdt_disable(); 233 - retval = 0; 234 - } 235 - if (options & WDIOS_ENABLECARD) { 236 - wdt_ping(); 237 - retval = 0; 238 - } 239 - return retval; 240 - } 241 - case WDIOC_KEEPALIVE: 242 - wdt_ping(); 243 - break; 244 - case WDIOC_SETTIMEOUT: 245 - if (get_user(timeval, p)) 246 - return -EFAULT; 247 - if (wdt_set_heartbeat(timeval)) 248 - return -EINVAL; 249 - wdt_ping(); 250 - /* Fall */ 251 - case WDIOC_GETTIMEOUT: 252 - return put_user(timeout, p); 253 - case WDIOC_GETTIMELEFT: 254 - timeval = wdt_get_time(); 255 - return put_user(timeval, p); 256 - default: 257 - return -ENOTTY; 258 - } 259 - return 0; 260 - } 261 - 262 - static int wdt_open(struct inode *inode, struct file *file) 263 - { 264 - if (test_and_set_bit(0, &wdt_is_open)) 265 - return -EBUSY; 266 - /* 267 - * Activate 268 - */ 269 - 270 - wdt_ping(); 271 - return nonseekable_open(inode, file); 272 - } 273 - 274 - static int wdt_close(struct inode *inode, struct file *file) 275 - { 276 - if (expect_close == 42) 277 - wdt_disable(); 278 - else { 279 - pr_crit("Unexpected close, not stopping watchdog!\n"); 280 - wdt_ping(); 281 - } 282 - expect_close = 0; 283 - clear_bit(0, &wdt_is_open); 284 - return 0; 285 192 } 286 193 287 194 /* 288 195 * Notifier for system down 289 196 */ 290 - 291 197 static int wdt_notify_sys(struct notifier_block *this, unsigned long code, 292 198 void *unused) 293 199 { 294 200 if (code == SYS_DOWN || code == SYS_HALT) 295 - wdt_disable(); /* Turn the WDT off */ 201 + wdt_set_time(0); /* Turn the WDT off */ 296 202 297 203 return NOTIFY_DONE; 298 204 } ··· 194 314 * Kernel Interfaces 195 315 */ 196 316 197 - static const struct file_operations wdt_fops = { 198 - .owner = THIS_MODULE, 199 - .llseek = no_llseek, 200 - .write = wdt_write, 201 - .unlocked_ioctl = wdt_ioctl, 202 - .open = wdt_open, 203 - .release = wdt_close, 317 + static struct watchdog_info wdt_info = { 318 + .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING | WDIOF_MAGICCLOSE, 319 + .identity = "W83627HF Watchdog", 204 320 }; 205 321 206 - static struct miscdevice wdt_miscdev = { 207 - .minor = WATCHDOG_MINOR, 208 - .name = "watchdog", 209 - .fops = &wdt_fops, 322 + static struct watchdog_ops wdt_ops = { 323 + .owner = THIS_MODULE, 324 + .start = wdt_start, 325 + .stop = wdt_stop, 326 + .set_timeout = wdt_set_timeout, 327 + .get_timeleft = wdt_get_time, 328 + }; 329 + 330 + static struct watchdog_device wdt_dev = { 331 + .info = &wdt_info, 332 + .ops = &wdt_ops, 333 + .timeout = WATCHDOG_TIMEOUT, 334 + .min_timeout = 1, 335 + .max_timeout = 255, 210 336 }; 211 337 212 338 /* ··· 230 344 231 345 pr_info("WDT driver for the Winbond(TM) W83627HF/THF/HG/DHG Super I/O chip initialising\n"); 232 346 233 - if (wdt_set_heartbeat(timeout)) { 234 - wdt_set_heartbeat(WATCHDOG_TIMEOUT); 235 - pr_info("timeout value must be 1 <= timeout <= 255, using %d\n", 236 - WATCHDOG_TIMEOUT); 237 - } 238 - 239 347 if (!request_region(wdt_io, 1, WATCHDOG_NAME)) { 240 348 pr_err("I/O address 0x%04x already in use\n", wdt_io); 241 - ret = -EIO; 242 - goto out; 349 + return -EIO; 243 350 } 244 351 245 - w83627hf_init(); 352 + watchdog_init_timeout(&wdt_dev, timeout, NULL); 353 + watchdog_set_nowayout(&wdt_dev, nowayout); 354 + 355 + w83627hf_init(&wdt_dev); 246 356 247 357 ret = register_reboot_notifier(&wdt_notifier); 248 358 if (ret != 0) { ··· 246 364 goto unreg_regions; 247 365 } 248 366 249 - ret = misc_register(&wdt_miscdev); 250 - if (ret != 0) { 251 - pr_err("cannot register miscdev on minor=%d (err=%d)\n", 252 - WATCHDOG_MINOR, ret); 367 + ret = watchdog_register_device(&wdt_dev); 368 + if (ret) 253 369 goto unreg_reboot; 254 - } 255 370 256 371 pr_info("initialized. timeout=%d sec (nowayout=%d)\n", 257 - timeout, nowayout); 372 + wdt_dev.timeout, nowayout); 258 373 259 - out: 260 374 return ret; 375 + 261 376 unreg_reboot: 262 377 unregister_reboot_notifier(&wdt_notifier); 263 378 unreg_regions: 264 379 release_region(wdt_io, 1); 265 - goto out; 380 + return ret; 266 381 } 267 382 268 383 static void __exit wdt_exit(void) 269 384 { 270 - misc_deregister(&wdt_miscdev); 385 + watchdog_unregister_device(&wdt_dev); 271 386 unregister_reboot_notifier(&wdt_notifier); 272 387 release_region(wdt_io, 1); 273 388 }