Loading drivers/watchdog/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -1138,6 +1138,7 @@ config ZVM_WATCHDOG config SH_WDT tristate "SuperH Watchdog" depends on SUPERH && (CPU_SH3 || CPU_SH4) select WATCHDOG_CORE help This driver adds watchdog support for the integrated watchdog in the SuperH processors. If you have one of these processors and wish Loading drivers/watchdog/shwdt.c +44 −154 Original line number Diff line number Diff line Loading @@ -27,12 +27,10 @@ #include <linux/types.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/ioport.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/uaccess.h> #include <asm/watchdog.h> #define DRV_NAME "sh-wdt" Loading Loading @@ -67,8 +65,6 @@ static int clock_division_ratio = WTCSR_CKS_4096; #define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) static const struct watchdog_info sh_wdt_info; static struct platform_device *sh_wdt_dev; static DEFINE_SPINLOCK(shwdt_lock); #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ Loading @@ -86,8 +82,9 @@ struct sh_wdt { char expect_close; }; static void sh_wdt_start(struct sh_wdt *wdt) static int sh_wdt_start(struct watchdog_device *wdt_dev) { struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev); unsigned long flags; u8 csr; Loading Loading @@ -121,10 +118,13 @@ static void sh_wdt_start(struct sh_wdt *wdt) sh_wdt_write_rstcsr(csr); #endif spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } static void sh_wdt_stop(struct sh_wdt *wdt) static int sh_wdt_stop(struct watchdog_device *wdt_dev) { struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev); unsigned long flags; u8 csr; Loading @@ -137,18 +137,22 @@ static void sh_wdt_stop(struct sh_wdt *wdt) sh_wdt_write_csr(csr); spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } static inline void sh_wdt_keepalive(struct sh_wdt *wdt) static int sh_wdt_keepalive(struct watchdog_device *wdt_dev) { unsigned long flags; spin_lock_irqsave(&shwdt_lock, flags); next_heartbeat = jiffies + (heartbeat * HZ); spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } static int sh_wdt_set_heartbeat(int t) static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t) { unsigned long flags; Loading @@ -157,7 +161,9 @@ static int sh_wdt_set_heartbeat(int t) spin_lock_irqsave(&shwdt_lock, flags); heartbeat = t; wdt_dev->timeout = t; spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } Loading @@ -183,123 +189,6 @@ static void sh_wdt_ping(unsigned long data) spin_unlock_irqrestore(&shwdt_lock, flags); } static int sh_wdt_open(struct inode *inode, struct file *file) { struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev); if (test_and_set_bit(0, &wdt->enabled)) return -EBUSY; if (nowayout) __module_get(THIS_MODULE); file->private_data = wdt; sh_wdt_start(wdt); return nonseekable_open(inode, file); } static int sh_wdt_close(struct inode *inode, struct file *file) { struct sh_wdt *wdt = file->private_data; if (wdt->expect_close == 42) { sh_wdt_stop(wdt); } else { dev_crit(wdt->dev, "Unexpected close, not " "stopping watchdog!\n"); sh_wdt_keepalive(wdt); } clear_bit(0, &wdt->enabled); wdt->expect_close = 0; return 0; } static ssize_t sh_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct sh_wdt *wdt = file->private_data; if (count) { if (!nowayout) { size_t i; wdt->expect_close = 0; for (i = 0; i != count; i++) { char c; if (get_user(c, buf + i)) return -EFAULT; if (c == 'V') wdt->expect_close = 42; } } sh_wdt_keepalive(wdt); } return count; } static long sh_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct sh_wdt *wdt = file->private_data; int new_heartbeat; int options, retval = -EINVAL; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, (int *)arg); case WDIOC_SETOPTIONS: if (get_user(options, (int *)arg)) return -EFAULT; if (options & WDIOS_DISABLECARD) { sh_wdt_stop(wdt); retval = 0; } if (options & WDIOS_ENABLECARD) { sh_wdt_start(wdt); retval = 0; } return retval; case WDIOC_KEEPALIVE: sh_wdt_keepalive(wdt); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_heartbeat, (int *)arg)) return -EFAULT; if (sh_wdt_set_heartbeat(new_heartbeat)) return -EINVAL; sh_wdt_keepalive(wdt); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(heartbeat, (int *)arg); default: return -ENOTTY; } return 0; } static const struct file_operations sh_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = sh_wdt_write, .unlocked_ioctl = sh_wdt_ioctl, .open = sh_wdt_open, .release = sh_wdt_close, }; static const struct watchdog_info sh_wdt_info = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, Loading @@ -307,10 +196,17 @@ static const struct watchdog_info sh_wdt_info = { .identity = "SH WDT", }; static struct miscdevice sh_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &sh_wdt_fops, static const struct watchdog_ops sh_wdt_ops = { .owner = THIS_MODULE, .start = sh_wdt_start, .stop = sh_wdt_stop, .ping = sh_wdt_keepalive, .set_timeout = sh_wdt_set_heartbeat, }; static struct watchdog_device sh_wdt_dev = { .info = &sh_wdt_info, .ops = &sh_wdt_ops, }; static int __devinit sh_wdt_probe(struct platform_device *pdev) Loading Loading @@ -348,13 +244,25 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev) goto out_err; } sh_wdt_miscdev.parent = wdt->dev; rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat); if (unlikely(rc)) { /* Default timeout if invalid */ sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT); dev_warn(&pdev->dev, "heartbeat value must be 1<=x<=3600, using %d\n", sh_wdt_dev.timeout); } dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n", sh_wdt_dev.timeout, nowayout); watchdog_set_nowayout(&sh_wdt_dev, nowayout); watchdog_set_drvdata(&sh_wdt_dev, wdt); rc = misc_register(&sh_wdt_miscdev); rc = watchdog_register_device(&sh_wdt_dev); if (unlikely(rc)) { dev_err(&pdev->dev, "Can't register miscdev on minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc); goto out_unmap; } Loading @@ -364,7 +272,6 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev) wdt->timer.expires = next_ping_period(clock_division_ratio); platform_set_drvdata(pdev, wdt); sh_wdt_dev = pdev; dev_info(&pdev->dev, "initialized.\n"); Loading @@ -387,9 +294,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); misc_deregister(&sh_wdt_miscdev); sh_wdt_dev = NULL; watchdog_unregister_device(&sh_wdt_dev); devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); devm_iounmap(&pdev->dev, wdt->base); Loading @@ -400,9 +305,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev) static void sh_wdt_shutdown(struct platform_device *pdev) { struct sh_wdt *wdt = platform_get_drvdata(pdev); sh_wdt_stop(wdt); sh_wdt_stop(&sh_wdt_dev); } static struct platform_driver sh_wdt_driver = { Loading @@ -418,8 +321,6 @@ static struct platform_driver sh_wdt_driver = { static int __init sh_wdt_init(void) { int rc; if (unlikely(clock_division_ratio < 0x5 || clock_division_ratio > 0x7)) { clock_division_ratio = WTCSR_CKS_4096; Loading @@ -428,17 +329,6 @@ static int __init sh_wdt_init(void) clock_division_ratio); } rc = sh_wdt_set_heartbeat(heartbeat); if (unlikely(rc)) { heartbeat = WATCHDOG_HEARTBEAT; pr_info("heartbeat value must be 1<=x<=3600, using %d\n", heartbeat); } pr_info("configured with heartbeat=%d sec (nowayout=%d)\n", heartbeat, nowayout); return platform_driver_register(&sh_wdt_driver); } Loading Loading
drivers/watchdog/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -1138,6 +1138,7 @@ config ZVM_WATCHDOG config SH_WDT tristate "SuperH Watchdog" depends on SUPERH && (CPU_SH3 || CPU_SH4) select WATCHDOG_CORE help This driver adds watchdog support for the integrated watchdog in the SuperH processors. If you have one of these processors and wish Loading
drivers/watchdog/shwdt.c +44 −154 Original line number Diff line number Diff line Loading @@ -27,12 +27,10 @@ #include <linux/types.h> #include <linux/miscdevice.h> #include <linux/watchdog.h> #include <linux/ioport.h> #include <linux/fs.h> #include <linux/mm.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/uaccess.h> #include <asm/watchdog.h> #define DRV_NAME "sh-wdt" Loading Loading @@ -67,8 +65,6 @@ static int clock_division_ratio = WTCSR_CKS_4096; #define next_ping_period(cks) (jiffies + msecs_to_jiffies(cks - 4)) static const struct watchdog_info sh_wdt_info; static struct platform_device *sh_wdt_dev; static DEFINE_SPINLOCK(shwdt_lock); #define WATCHDOG_HEARTBEAT 30 /* 30 sec default heartbeat */ Loading @@ -86,8 +82,9 @@ struct sh_wdt { char expect_close; }; static void sh_wdt_start(struct sh_wdt *wdt) static int sh_wdt_start(struct watchdog_device *wdt_dev) { struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev); unsigned long flags; u8 csr; Loading Loading @@ -121,10 +118,13 @@ static void sh_wdt_start(struct sh_wdt *wdt) sh_wdt_write_rstcsr(csr); #endif spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } static void sh_wdt_stop(struct sh_wdt *wdt) static int sh_wdt_stop(struct watchdog_device *wdt_dev) { struct sh_wdt *wdt = watchdog_get_drvdata(wdt_dev); unsigned long flags; u8 csr; Loading @@ -137,18 +137,22 @@ static void sh_wdt_stop(struct sh_wdt *wdt) sh_wdt_write_csr(csr); spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } static inline void sh_wdt_keepalive(struct sh_wdt *wdt) static int sh_wdt_keepalive(struct watchdog_device *wdt_dev) { unsigned long flags; spin_lock_irqsave(&shwdt_lock, flags); next_heartbeat = jiffies + (heartbeat * HZ); spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } static int sh_wdt_set_heartbeat(int t) static int sh_wdt_set_heartbeat(struct watchdog_device *wdt_dev, unsigned t) { unsigned long flags; Loading @@ -157,7 +161,9 @@ static int sh_wdt_set_heartbeat(int t) spin_lock_irqsave(&shwdt_lock, flags); heartbeat = t; wdt_dev->timeout = t; spin_unlock_irqrestore(&shwdt_lock, flags); return 0; } Loading @@ -183,123 +189,6 @@ static void sh_wdt_ping(unsigned long data) spin_unlock_irqrestore(&shwdt_lock, flags); } static int sh_wdt_open(struct inode *inode, struct file *file) { struct sh_wdt *wdt = platform_get_drvdata(sh_wdt_dev); if (test_and_set_bit(0, &wdt->enabled)) return -EBUSY; if (nowayout) __module_get(THIS_MODULE); file->private_data = wdt; sh_wdt_start(wdt); return nonseekable_open(inode, file); } static int sh_wdt_close(struct inode *inode, struct file *file) { struct sh_wdt *wdt = file->private_data; if (wdt->expect_close == 42) { sh_wdt_stop(wdt); } else { dev_crit(wdt->dev, "Unexpected close, not " "stopping watchdog!\n"); sh_wdt_keepalive(wdt); } clear_bit(0, &wdt->enabled); wdt->expect_close = 0; return 0; } static ssize_t sh_wdt_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { struct sh_wdt *wdt = file->private_data; if (count) { if (!nowayout) { size_t i; wdt->expect_close = 0; for (i = 0; i != count; i++) { char c; if (get_user(c, buf + i)) return -EFAULT; if (c == 'V') wdt->expect_close = 42; } } sh_wdt_keepalive(wdt); } return count; } static long sh_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct sh_wdt *wdt = file->private_data; int new_heartbeat; int options, retval = -EINVAL; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user((struct watchdog_info *)arg, &sh_wdt_info, sizeof(sh_wdt_info)) ? -EFAULT : 0; case WDIOC_GETSTATUS: case WDIOC_GETBOOTSTATUS: return put_user(0, (int *)arg); case WDIOC_SETOPTIONS: if (get_user(options, (int *)arg)) return -EFAULT; if (options & WDIOS_DISABLECARD) { sh_wdt_stop(wdt); retval = 0; } if (options & WDIOS_ENABLECARD) { sh_wdt_start(wdt); retval = 0; } return retval; case WDIOC_KEEPALIVE: sh_wdt_keepalive(wdt); return 0; case WDIOC_SETTIMEOUT: if (get_user(new_heartbeat, (int *)arg)) return -EFAULT; if (sh_wdt_set_heartbeat(new_heartbeat)) return -EINVAL; sh_wdt_keepalive(wdt); /* Fall */ case WDIOC_GETTIMEOUT: return put_user(heartbeat, (int *)arg); default: return -ENOTTY; } return 0; } static const struct file_operations sh_wdt_fops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = sh_wdt_write, .unlocked_ioctl = sh_wdt_ioctl, .open = sh_wdt_open, .release = sh_wdt_close, }; static const struct watchdog_info sh_wdt_info = { .options = WDIOF_KEEPALIVEPING | WDIOF_SETTIMEOUT | WDIOF_MAGICCLOSE, Loading @@ -307,10 +196,17 @@ static const struct watchdog_info sh_wdt_info = { .identity = "SH WDT", }; static struct miscdevice sh_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &sh_wdt_fops, static const struct watchdog_ops sh_wdt_ops = { .owner = THIS_MODULE, .start = sh_wdt_start, .stop = sh_wdt_stop, .ping = sh_wdt_keepalive, .set_timeout = sh_wdt_set_heartbeat, }; static struct watchdog_device sh_wdt_dev = { .info = &sh_wdt_info, .ops = &sh_wdt_ops, }; static int __devinit sh_wdt_probe(struct platform_device *pdev) Loading Loading @@ -348,13 +244,25 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev) goto out_err; } sh_wdt_miscdev.parent = wdt->dev; rc = sh_wdt_set_heartbeat(&sh_wdt_dev, heartbeat); if (unlikely(rc)) { /* Default timeout if invalid */ sh_wdt_set_heartbeat(&sh_wdt_dev, WATCHDOG_HEARTBEAT); dev_warn(&pdev->dev, "heartbeat value must be 1<=x<=3600, using %d\n", sh_wdt_dev.timeout); } dev_info(&pdev->dev, "configured with heartbeat=%d sec (nowayout=%d)\n", sh_wdt_dev.timeout, nowayout); watchdog_set_nowayout(&sh_wdt_dev, nowayout); watchdog_set_drvdata(&sh_wdt_dev, wdt); rc = misc_register(&sh_wdt_miscdev); rc = watchdog_register_device(&sh_wdt_dev); if (unlikely(rc)) { dev_err(&pdev->dev, "Can't register miscdev on minor=%d (err=%d)\n", sh_wdt_miscdev.minor, rc); dev_err(&pdev->dev, "Can't register watchdog (err=%d)\n", rc); goto out_unmap; } Loading @@ -364,7 +272,6 @@ static int __devinit sh_wdt_probe(struct platform_device *pdev) wdt->timer.expires = next_ping_period(clock_division_ratio); platform_set_drvdata(pdev, wdt); sh_wdt_dev = pdev; dev_info(&pdev->dev, "initialized.\n"); Loading @@ -387,9 +294,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); misc_deregister(&sh_wdt_miscdev); sh_wdt_dev = NULL; watchdog_unregister_device(&sh_wdt_dev); devm_release_mem_region(&pdev->dev, res->start, resource_size(res)); devm_iounmap(&pdev->dev, wdt->base); Loading @@ -400,9 +305,7 @@ static int __devexit sh_wdt_remove(struct platform_device *pdev) static void sh_wdt_shutdown(struct platform_device *pdev) { struct sh_wdt *wdt = platform_get_drvdata(pdev); sh_wdt_stop(wdt); sh_wdt_stop(&sh_wdt_dev); } static struct platform_driver sh_wdt_driver = { Loading @@ -418,8 +321,6 @@ static struct platform_driver sh_wdt_driver = { static int __init sh_wdt_init(void) { int rc; if (unlikely(clock_division_ratio < 0x5 || clock_division_ratio > 0x7)) { clock_division_ratio = WTCSR_CKS_4096; Loading @@ -428,17 +329,6 @@ static int __init sh_wdt_init(void) clock_division_ratio); } rc = sh_wdt_set_heartbeat(heartbeat); if (unlikely(rc)) { heartbeat = WATCHDOG_HEARTBEAT; pr_info("heartbeat value must be 1<=x<=3600, using %d\n", heartbeat); } pr_info("configured with heartbeat=%d sec (nowayout=%d)\n", heartbeat, nowayout); return platform_driver_register(&sh_wdt_driver); } Loading