--- zzzz-none-000/linux-3.10.107/drivers/watchdog/ath79_wdt.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/watchdog/ath79_wdt.c 2021-02-04 17:41:59.000000000 +0000 @@ -23,7 +23,6 @@ #include #include #include -#include #include #include #include @@ -36,7 +35,12 @@ #include #include #include +#include +#include +#include +#include +#include #define DRIVER_NAME "ath79-wdt" #define WDT_TIMEOUT 15 /* seconds */ @@ -71,6 +75,8 @@ static int boot_status; static int max_timeout; static void __iomem *wdt_base; +static unsigned long long last_pet; +static struct dentry *ath79_wdt_dbg_dir; static inline void ath79_wdt_wr(unsigned reg, u32 val) { @@ -87,6 +93,7 @@ ath79_wdt_wr(WDOG_REG_TIMER, wdt_freq * timeout); /* flush write */ ath79_wdt_rr(WDOG_REG_TIMER); + last_pet = sched_clock(); } static inline void ath79_wdt_enable(void) @@ -101,11 +108,30 @@ */ udelay(2); +#ifdef CONFIG_KEXEC + ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_GPI); +#else ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_FCR); +#endif /* flush write */ ath79_wdt_rr(WDOG_REG_CTRL); } +static irqreturn_t ath79_wdt_irq_handler(int irq, void *dev_id) +{ + unsigned long nanosec_rem; + unsigned long long t = sched_clock(); + struct task_struct *tsk; + + ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_NONE); + pr_info("Watchdog bark! Now = %llu \n", t); + pr_info("Watchdog last pet at %llu \n", last_pet); + pr_info("\n ================================== \n"); + panic("BUG : ATH_WDT_TIMEOUT "); + + return IRQ_HANDLED; +} + static inline void ath79_wdt_disable(void) { ath79_wdt_wr(WDOG_REG_CTRL, WDOG_CTRL_ACTION_NONE); @@ -115,10 +141,14 @@ static int ath79_wdt_set_timeout(int val) { - if (val < 1 || val > max_timeout) + if (val < 1) return -EINVAL; - timeout = val; + if (val > max_timeout) + timeout = max_timeout; + else + timeout = val; + ath79_wdt_keepalive(); return 0; @@ -126,10 +156,20 @@ static int ath79_wdt_open(struct inode *inode, struct file *file) { + int ret; + if (test_and_set_bit(WDT_FLAGS_BUSY, &wdt_flags)) return -EBUSY; clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + + ret = request_irq(ATH79_MISC_IRQ_WDOG, ath79_wdt_irq_handler, 0, + "ath79_wdt_irq", NULL); + if (ret) { + pr_err("ATH79 WDT IRQ Request failed! err %d\n", ret); + return -EBUSY; + } + ath79_wdt_enable(); return nonseekable_open(inode, file); @@ -146,6 +186,7 @@ clear_bit(WDT_FLAGS_BUSY, &wdt_flags); clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags); + free_irq(ATH79_MISC_IRQ_WDOG, NULL); return 0; } @@ -248,11 +289,32 @@ .fops = &ath79_wdt_fops, }; +static int ath79_wdt_debugfs_read(void *data, u64 *val) +{ + *val = ath79_wdt_rr(WDOG_REG_CTRL); + return 0; +} + +static int ath79_wdt_debugfs_write(void *data, u64 val) +{ + if (val < WDOG_CTRL_ACTION_NONE || val > WDOG_CTRL_ACTION_FCR) + return -EINVAL; + + ath79_wdt_wr(WDOG_REG_CTRL, val); + /* flush write */ + ath79_wdt_rr(WDOG_REG_CTRL); + return 0; +} +DEFINE_SIMPLE_ATTRIBUTE(ath79_wdt_dbg_fops, ath79_wdt_debugfs_read, + ath79_wdt_debugfs_write, "%llu\n"); + static int ath79_wdt_probe(struct platform_device *pdev) { struct resource *res; u32 ctrl; int err; + u8 wdtboot; + struct dentry *dbg_file_action; if (wdt_base) return -EBUSY; @@ -266,7 +328,7 @@ if (IS_ERR(wdt_clk)) return PTR_ERR(wdt_clk); - err = clk_enable(wdt_clk); + err = clk_prepare_enable(wdt_clk); if (err) return err; @@ -286,6 +348,10 @@ ctrl = ath79_wdt_rr(WDOG_REG_CTRL); boot_status = (ctrl & WDOG_CTRL_LAST_RESET) ? WDIOF_CARDRESET : 0; + wdtboot = (ctrl & WDOG_CTRL_LAST_RESET) ? 1 : 0; + pr_info("WDOG_REG_CTRL: 0x%x\n ", ctrl); + if (wdtboot) + pr_info("Last system reboot was due to WDOG\n"); err = misc_register(&ath79_wdt_miscdev); if (err) { @@ -294,21 +360,47 @@ goto err_clk_disable; } + ath79_wdt_dbg_dir = debugfs_create_dir("ath79_wdt", NULL); + if (IS_ERR_OR_NULL(ath79_wdt_dbg_dir)) { + err = PTR_ERR_OR_ZERO(ath79_wdt_dbg_dir); + if (err == 0) + err = -EINVAL; + + pr_err("%s: ath79_wdt debugfs dir creation failed err=%d\n", + __func__, err); + goto err_clk_disable; + } + + dbg_file_action = debugfs_create_file("action", S_IRUGO | S_IWUSR, + ath79_wdt_dbg_dir, NULL, &ath79_wdt_dbg_fops); + if (IS_ERR_OR_NULL(dbg_file_action)) { + err = PTR_ERR_OR_ZERO(ath79_wdt_dbg_dir); + if (err == 0) + err = -EINVAL; + + pr_err("%s: file creation in ath79_wdt dir failed err=%d\n", + __func__, err); + goto err_dir_remove; + } + return 0; +err_dir_remove: + debugfs_remove(ath79_wdt_dbg_dir); err_clk_disable: - clk_disable(wdt_clk); + clk_disable_unprepare(wdt_clk); return err; } static int ath79_wdt_remove(struct platform_device *pdev) { + debugfs_remove_recursive(ath79_wdt_dbg_dir); misc_deregister(&ath79_wdt_miscdev); - clk_disable(wdt_clk); + clk_disable_unprepare(wdt_clk); return 0; } -static void ath97_wdt_shutdown(struct platform_device *pdev) +static void ath79_wdt_shutdown(struct platform_device *pdev) { ath79_wdt_disable(); } @@ -324,10 +416,9 @@ static struct platform_driver ath79_wdt_driver = { .probe = ath79_wdt_probe, .remove = ath79_wdt_remove, - .shutdown = ath97_wdt_shutdown, + .shutdown = ath79_wdt_shutdown, .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, .of_match_table = of_match_ptr(ath79_wdt_match), }, }; @@ -339,4 +430,3 @@ MODULE_AUTHOR("Imre Kaloz