Loading drivers/watchdog/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -1145,6 +1145,7 @@ config PIKA_WDT config BOOKE_WDT tristate "PowerPC Book-E Watchdog Timer" depends on BOOKE || 4xx select WATCHDOG_CORE ---help--- Watchdog driver for PowerPC Book-E chips, such as the Freescale MPC85xx SOCs and the IBM PowerPC 440. Loading drivers/watchdog/booke_wdt.c +65 −120 Original line number Diff line number Diff line Loading @@ -15,12 +15,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/fs.h> #include <linux/smp.h> #include <linux/miscdevice.h> #include <linux/notifier.h> #include <linux/watchdog.h> #include <linux/uaccess.h> #include <asm/reg_booke.h> #include <asm/time.h> Loading @@ -45,7 +41,7 @@ u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT; #define WDTP_MASK (TCR_WP_MASK) #endif static DEFINE_SPINLOCK(booke_wdt_lock); #ifdef CONFIG_PPC_FSL_BOOK3E /* For the specified period, determine the number of seconds * corresponding to the reset time. There will be a watchdog Loading Loading @@ -86,6 +82,24 @@ static unsigned int sec_to_period(unsigned int secs) return 0; } #define MAX_WDT_TIMEOUT period_to_sec(1) #else /* CONFIG_PPC_FSL_BOOK3E */ static unsigned long long period_to_sec(unsigned int period) { return period; } static unsigned int sec_to_period(unsigned int secs) { return secs; } #define MAX_WDT_TIMEOUT 3 /* from Kconfig */ #endif /* !CONFIG_PPC_FSL_BOOK3E */ static void __booke_wdt_set(void *data) { u32 val; Loading @@ -107,9 +121,11 @@ static void __booke_wdt_ping(void *data) mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); } static void booke_wdt_ping(void) static int booke_wdt_ping(struct watchdog_device *wdog) { on_each_cpu(__booke_wdt_ping, NULL, 0); return 0; } static void __booke_wdt_enable(void *data) Loading Loading @@ -146,152 +162,81 @@ static void __booke_wdt_disable(void *data) } static ssize_t booke_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { booke_wdt_ping(); return count; } static struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "PowerPC Book-E Watchdog", }; static long booke_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static void __booke_wdt_start(struct watchdog_device *wdog) { u32 tmp = 0; u32 __user *p = (u32 __user *)arg; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(p, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: return put_user(0, p); case WDIOC_GETBOOTSTATUS: /* XXX: something is clearing TSR */ tmp = mfspr(SPRN_TSR) & TSR_WRS(3); /* returns CARDRESET if last reset was caused by the WDT */ return put_user((tmp ? WDIOF_CARDRESET : 0), p); case WDIOC_SETOPTIONS: if (get_user(tmp, p)) return -EFAULT; if (tmp == WDIOS_ENABLECARD) { booke_wdt_ping(); break; } else return -EINVAL; return 0; case WDIOC_KEEPALIVE: booke_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(tmp, p)) return -EFAULT; #ifdef CONFIG_PPC_FSL_BOOK3E /* period of 1 gives the largest possible timeout */ if (tmp > period_to_sec(1)) return -EINVAL; booke_wdt_period = sec_to_period(tmp); #else booke_wdt_period = tmp; #endif booke_wdt_set(); /* Fall */ case WDIOC_GETTIMEOUT: #ifdef CONFIG_FSL_BOOKE return put_user(period_to_sec(booke_wdt_period), p); #else return put_user(booke_wdt_period, p); #endif default: return -ENOTTY; } return 0; on_each_cpu(__booke_wdt_enable, NULL, 0); pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout); } /* wdt_is_active stores whether or not the /dev/watchdog device is opened */ static unsigned long wdt_is_active; static int booke_wdt_open(struct inode *inode, struct file *file) static int booke_wdt_start(struct watchdog_device *wdog) { /* /dev/watchdog can only be opened once */ if (test_and_set_bit(0, &wdt_is_active)) return -EBUSY; spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 0) { booke_wdt_enabled = 1; on_each_cpu(__booke_wdt_enable, NULL, 0); pr_debug("watchdog enabled (timeout = %llu sec)\n", period_to_sec(booke_wdt_period)); __booke_wdt_start(wdog); } spin_unlock(&booke_wdt_lock); return nonseekable_open(inode, file); return 0; } static int booke_wdt_release(struct inode *inode, struct file *file) static int booke_wdt_stop(struct watchdog_device *wdog) { #ifndef CONFIG_WATCHDOG_NOWAYOUT /* Normally, the watchdog is disabled when /dev/watchdog is closed, but * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the * watchdog should remain enabled. So we disable it only if * CONFIG_WATCHDOG_NOWAYOUT is not defined. */ on_each_cpu(__booke_wdt_disable, NULL, 0); booke_wdt_enabled = 0; pr_debug("watchdog disabled\n"); #endif clear_bit(0, &wdt_is_active); return 0; } static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, unsigned int timeout) { if (timeout > MAX_WDT_TIMEOUT) return -EINVAL; booke_wdt_period = sec_to_period(timeout); wdt_dev->timeout = timeout; booke_wdt_set(); return 0; } static const struct file_operations booke_wdt_fops = { static struct watchdog_info booke_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "PowerPC Book-E Watchdog", }; static struct watchdog_ops booke_wdt_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = booke_wdt_write, .unlocked_ioctl = booke_wdt_ioctl, .open = booke_wdt_open, .release = booke_wdt_release, .start = booke_wdt_start, .stop = booke_wdt_stop, .ping = booke_wdt_ping, .set_timeout = booke_wdt_set_timeout, }; static struct miscdevice booke_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &booke_wdt_fops, static struct watchdog_device booke_wdt_dev = { .info = &booke_wdt_info, .ops = &booke_wdt_ops, .min_timeout = 1, .max_timeout = 0xFFFF }; static void __exit booke_wdt_exit(void) { misc_deregister(&booke_wdt_miscdev); watchdog_unregister_device(&booke_wdt_dev); } static int __init booke_wdt_init(void) { int ret = 0; bool nowayout = WATCHDOG_NOWAYOUT; pr_info("powerpc book-e watchdog driver loaded\n"); ident.firmware_version = cur_cpu_spec->pvr_value; ret = misc_register(&booke_wdt_miscdev); if (ret) { pr_err("cannot register device (minor=%u, ret=%i)\n", WATCHDOG_MINOR, ret); return ret; } spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 1) { pr_info("watchdog enabled (timeout = %llu sec)\n", period_to_sec(booke_wdt_period)); on_each_cpu(__booke_wdt_enable, NULL, 0); } spin_unlock(&booke_wdt_lock); booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value; booke_wdt_set_timeout(&booke_wdt_dev, period_to_sec(CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT)); watchdog_set_nowayout(&booke_wdt_dev, nowayout); if (booke_wdt_enabled) __booke_wdt_start(&booke_wdt_dev); ret = watchdog_register_device(&booke_wdt_dev); return ret; } Loading Loading
drivers/watchdog/Kconfig +1 −0 Original line number Diff line number Diff line Loading @@ -1145,6 +1145,7 @@ config PIKA_WDT config BOOKE_WDT tristate "PowerPC Book-E Watchdog Timer" depends on BOOKE || 4xx select WATCHDOG_CORE ---help--- Watchdog driver for PowerPC Book-E chips, such as the Freescale MPC85xx SOCs and the IBM PowerPC 440. Loading
drivers/watchdog/booke_wdt.c +65 −120 Original line number Diff line number Diff line Loading @@ -15,12 +15,8 @@ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt #include <linux/module.h> #include <linux/fs.h> #include <linux/smp.h> #include <linux/miscdevice.h> #include <linux/notifier.h> #include <linux/watchdog.h> #include <linux/uaccess.h> #include <asm/reg_booke.h> #include <asm/time.h> Loading @@ -45,7 +41,7 @@ u32 booke_wdt_period = CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT; #define WDTP_MASK (TCR_WP_MASK) #endif static DEFINE_SPINLOCK(booke_wdt_lock); #ifdef CONFIG_PPC_FSL_BOOK3E /* For the specified period, determine the number of seconds * corresponding to the reset time. There will be a watchdog Loading Loading @@ -86,6 +82,24 @@ static unsigned int sec_to_period(unsigned int secs) return 0; } #define MAX_WDT_TIMEOUT period_to_sec(1) #else /* CONFIG_PPC_FSL_BOOK3E */ static unsigned long long period_to_sec(unsigned int period) { return period; } static unsigned int sec_to_period(unsigned int secs) { return secs; } #define MAX_WDT_TIMEOUT 3 /* from Kconfig */ #endif /* !CONFIG_PPC_FSL_BOOK3E */ static void __booke_wdt_set(void *data) { u32 val; Loading @@ -107,9 +121,11 @@ static void __booke_wdt_ping(void *data) mtspr(SPRN_TSR, TSR_ENW|TSR_WIS); } static void booke_wdt_ping(void) static int booke_wdt_ping(struct watchdog_device *wdog) { on_each_cpu(__booke_wdt_ping, NULL, 0); return 0; } static void __booke_wdt_enable(void *data) Loading Loading @@ -146,152 +162,81 @@ static void __booke_wdt_disable(void *data) } static ssize_t booke_wdt_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) { booke_wdt_ping(); return count; } static struct watchdog_info ident = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "PowerPC Book-E Watchdog", }; static long booke_wdt_ioctl(struct file *file, unsigned int cmd, unsigned long arg) static void __booke_wdt_start(struct watchdog_device *wdog) { u32 tmp = 0; u32 __user *p = (u32 __user *)arg; switch (cmd) { case WDIOC_GETSUPPORT: return copy_to_user(p, &ident, sizeof(ident)) ? -EFAULT : 0; case WDIOC_GETSTATUS: return put_user(0, p); case WDIOC_GETBOOTSTATUS: /* XXX: something is clearing TSR */ tmp = mfspr(SPRN_TSR) & TSR_WRS(3); /* returns CARDRESET if last reset was caused by the WDT */ return put_user((tmp ? WDIOF_CARDRESET : 0), p); case WDIOC_SETOPTIONS: if (get_user(tmp, p)) return -EFAULT; if (tmp == WDIOS_ENABLECARD) { booke_wdt_ping(); break; } else return -EINVAL; return 0; case WDIOC_KEEPALIVE: booke_wdt_ping(); return 0; case WDIOC_SETTIMEOUT: if (get_user(tmp, p)) return -EFAULT; #ifdef CONFIG_PPC_FSL_BOOK3E /* period of 1 gives the largest possible timeout */ if (tmp > period_to_sec(1)) return -EINVAL; booke_wdt_period = sec_to_period(tmp); #else booke_wdt_period = tmp; #endif booke_wdt_set(); /* Fall */ case WDIOC_GETTIMEOUT: #ifdef CONFIG_FSL_BOOKE return put_user(period_to_sec(booke_wdt_period), p); #else return put_user(booke_wdt_period, p); #endif default: return -ENOTTY; } return 0; on_each_cpu(__booke_wdt_enable, NULL, 0); pr_debug("watchdog enabled (timeout = %u sec)\n", wdog->timeout); } /* wdt_is_active stores whether or not the /dev/watchdog device is opened */ static unsigned long wdt_is_active; static int booke_wdt_open(struct inode *inode, struct file *file) static int booke_wdt_start(struct watchdog_device *wdog) { /* /dev/watchdog can only be opened once */ if (test_and_set_bit(0, &wdt_is_active)) return -EBUSY; spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 0) { booke_wdt_enabled = 1; on_each_cpu(__booke_wdt_enable, NULL, 0); pr_debug("watchdog enabled (timeout = %llu sec)\n", period_to_sec(booke_wdt_period)); __booke_wdt_start(wdog); } spin_unlock(&booke_wdt_lock); return nonseekable_open(inode, file); return 0; } static int booke_wdt_release(struct inode *inode, struct file *file) static int booke_wdt_stop(struct watchdog_device *wdog) { #ifndef CONFIG_WATCHDOG_NOWAYOUT /* Normally, the watchdog is disabled when /dev/watchdog is closed, but * if CONFIG_WATCHDOG_NOWAYOUT is defined, then it means that the * watchdog should remain enabled. So we disable it only if * CONFIG_WATCHDOG_NOWAYOUT is not defined. */ on_each_cpu(__booke_wdt_disable, NULL, 0); booke_wdt_enabled = 0; pr_debug("watchdog disabled\n"); #endif clear_bit(0, &wdt_is_active); return 0; } static int booke_wdt_set_timeout(struct watchdog_device *wdt_dev, unsigned int timeout) { if (timeout > MAX_WDT_TIMEOUT) return -EINVAL; booke_wdt_period = sec_to_period(timeout); wdt_dev->timeout = timeout; booke_wdt_set(); return 0; } static const struct file_operations booke_wdt_fops = { static struct watchdog_info booke_wdt_info = { .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING, .identity = "PowerPC Book-E Watchdog", }; static struct watchdog_ops booke_wdt_ops = { .owner = THIS_MODULE, .llseek = no_llseek, .write = booke_wdt_write, .unlocked_ioctl = booke_wdt_ioctl, .open = booke_wdt_open, .release = booke_wdt_release, .start = booke_wdt_start, .stop = booke_wdt_stop, .ping = booke_wdt_ping, .set_timeout = booke_wdt_set_timeout, }; static struct miscdevice booke_wdt_miscdev = { .minor = WATCHDOG_MINOR, .name = "watchdog", .fops = &booke_wdt_fops, static struct watchdog_device booke_wdt_dev = { .info = &booke_wdt_info, .ops = &booke_wdt_ops, .min_timeout = 1, .max_timeout = 0xFFFF }; static void __exit booke_wdt_exit(void) { misc_deregister(&booke_wdt_miscdev); watchdog_unregister_device(&booke_wdt_dev); } static int __init booke_wdt_init(void) { int ret = 0; bool nowayout = WATCHDOG_NOWAYOUT; pr_info("powerpc book-e watchdog driver loaded\n"); ident.firmware_version = cur_cpu_spec->pvr_value; ret = misc_register(&booke_wdt_miscdev); if (ret) { pr_err("cannot register device (minor=%u, ret=%i)\n", WATCHDOG_MINOR, ret); return ret; } spin_lock(&booke_wdt_lock); if (booke_wdt_enabled == 1) { pr_info("watchdog enabled (timeout = %llu sec)\n", period_to_sec(booke_wdt_period)); on_each_cpu(__booke_wdt_enable, NULL, 0); } spin_unlock(&booke_wdt_lock); booke_wdt_info.firmware_version = cur_cpu_spec->pvr_value; booke_wdt_set_timeout(&booke_wdt_dev, period_to_sec(CONFIG_BOOKE_WDT_DEFAULT_TIMEOUT)); watchdog_set_nowayout(&booke_wdt_dev, nowayout); if (booke_wdt_enabled) __booke_wdt_start(&booke_wdt_dev); ret = watchdog_register_device(&booke_wdt_dev); return ret; } Loading