Files
openwrt_deco_e4r/target/linux/ar71xx/patches-3.3/985-QCA-MIPS-ath79-wdt-dynamic-action-select.patch

143 lines
3.9 KiB
Diff

diff --git a/drivers/watchdog/ath79_wdt.c b/drivers/watchdog/ath79_wdt.c
index bf79909..eff7903 100644
--- a/drivers/watchdog/ath79_wdt.c
+++ b/drivers/watchdog/ath79_wdt.c
@@ -31,9 +31,14 @@
#include <linux/watchdog.h>
#include <linux/clk.h>
#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/jiffies.h>
+#include <linux/sched.h>
+#include <linux/debugfs.h>
#include <asm/mach-ath79/ath79.h>
#include <asm/mach-ath79/ar71xx_regs.h>
+#include <asm/mach-ath79/irq.h>
#define DRIVER_NAME "ath79-wdt"
@@ -65,12 +70,15 @@ static struct clk *wdt_clk;
static unsigned long wdt_freq;
static int boot_status;
static int max_timeout;
+static unsigned long long last_pet;
+static struct dentry *ath79_wdt_dbg_dir;
static inline void ath79_wdt_keepalive(void)
{
ath79_reset_wr(AR71XX_RESET_REG_WDOG, wdt_freq * timeout);
/* flush write */
ath79_reset_rr(AR71XX_RESET_REG_WDOG);
+ last_pet = sched_clock();
}
static inline void ath79_wdt_enable(void)
@@ -88,6 +96,22 @@ static inline void ath79_wdt_enable(void)
ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, WDOG_CTRL_ACTION_FCR);
/* flush write */
ath79_reset_rr(AR71XX_RESET_REG_WDOG_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_reset_wr(AR71XX_RESET_REG_WDOG_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)
@@ -110,10 +134,20 @@ static int ath79_wdt_set_timeout(int val)
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);
@@ -131,6 +165,7 @@ static int ath79_wdt_release(struct inode *inode, struct file *file)
clear_bit(WDT_FLAGS_BUSY, &wdt_flags);
clear_bit(WDT_FLAGS_EXPECT_CLOSE, &wdt_flags);
+ free_irq(ATH79_MISC_IRQ_WDOG,NULL);
return 0;
}
@@ -287,22 +322,52 @@ static int __devexit ath79_wdt_remove(struct platform_device *pdev)
return 0;
}
-static void ath97_wdt_shutdown(struct platform_device *pdev)
+static void ath79_wdt_shutdown(struct platform_device *pdev)
{
ath79_wdt_disable();
}
static struct platform_driver ath79_wdt_driver = {
.remove = __devexit_p(ath79_wdt_remove),
- .shutdown = ath97_wdt_shutdown,
+ .shutdown = ath79_wdt_shutdown,
.driver = {
.name = DRIVER_NAME,
.owner = THIS_MODULE,
},
};
+static int ath79_wdt_debugfs_read(void *data, u64 *val)
+{
+ pr_info(" ath79_wdt ::Action = %d \n",
+ ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL));
+ return 0;
+}
+
+static int ath79_wdt_debugfs_write(void *data, u64 val)
+{
+ /* check for validity of the option for action. valid range is 0 till 3 */
+ if (val < WDOG_CTRL_ACTION_NONE || val > WDOG_CTRL_ACTION_FCR)
+ return -EINVAL;
+
+ ath79_reset_wr(AR71XX_RESET_REG_WDOG_CTRL, val);
+ /* flush write */
+ ath79_reset_rr(AR71XX_RESET_REG_WDOG_CTRL);
+ return 0;
+}
+DEFINE_SIMPLE_ATTRIBUTE(ath79_wdt_dbg_fops,ath79_wdt_debugfs_read,
+ ath79_wdt_debugfs_write, "%llu\n");
+
static int __init ath79_wdt_init(void)
{
+ ath79_wdt_dbg_dir = debugfs_create_dir("ath79_wdt", NULL);
+ if (IS_ERR_OR_NULL(ath79_wdt_dbg_dir)) {
+ pr_err("%s: ath79_wdt_dbg_dir debugfs dir creation failed\n", __func__);
+ return -EINVAL;
+ }
+
+ (void) debugfs_create_file("action", S_IRUGO | S_IWUSR,
+ ath79_wdt_dbg_dir, NULL, &ath79_wdt_dbg_fops);
+
return platform_driver_probe(&ath79_wdt_driver, ath79_wdt_probe);
}
module_init(ath79_wdt_init);