watchdog: dw_wdt: add restart handler support
The kernel core now provides an API to trigger a system restart. Register with it to support restarting the system via. watchdog. Signed-off-by: Jisheng Zhang <jszhang@marvell.com> Reviewed-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Wim Van Sebroeck <wim@iguana.be>
This commit is contained in:
parent
69a160a054
commit
31228f43ab
@ -21,6 +21,7 @@
|
|||||||
|
|
||||||
#include <linux/bitops.h>
|
#include <linux/bitops.h>
|
||||||
#include <linux/clk.h>
|
#include <linux/clk.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
#include <linux/err.h>
|
#include <linux/err.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
@ -29,9 +30,11 @@
|
|||||||
#include <linux/miscdevice.h>
|
#include <linux/miscdevice.h>
|
||||||
#include <linux/module.h>
|
#include <linux/module.h>
|
||||||
#include <linux/moduleparam.h>
|
#include <linux/moduleparam.h>
|
||||||
|
#include <linux/notifier.h>
|
||||||
#include <linux/of.h>
|
#include <linux/of.h>
|
||||||
#include <linux/pm.h>
|
#include <linux/pm.h>
|
||||||
#include <linux/platform_device.h>
|
#include <linux/platform_device.h>
|
||||||
|
#include <linux/reboot.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <linux/timer.h>
|
#include <linux/timer.h>
|
||||||
#include <linux/uaccess.h>
|
#include <linux/uaccess.h>
|
||||||
@ -63,6 +66,7 @@ static struct {
|
|||||||
unsigned long next_heartbeat;
|
unsigned long next_heartbeat;
|
||||||
struct timer_list timer;
|
struct timer_list timer;
|
||||||
int expect_close;
|
int expect_close;
|
||||||
|
struct notifier_block restart_handler;
|
||||||
} dw_wdt;
|
} dw_wdt;
|
||||||
|
|
||||||
static inline int dw_wdt_is_enabled(void)
|
static inline int dw_wdt_is_enabled(void)
|
||||||
@ -121,6 +125,26 @@ static void dw_wdt_keepalive(void)
|
|||||||
WDOG_COUNTER_RESTART_REG_OFFSET);
|
WDOG_COUNTER_RESTART_REG_OFFSET);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int dw_wdt_restart_handle(struct notifier_block *this,
|
||||||
|
unsigned long mode, void *cmd)
|
||||||
|
{
|
||||||
|
u32 val;
|
||||||
|
|
||||||
|
writel(0, dw_wdt.regs + WDOG_TIMEOUT_RANGE_REG_OFFSET);
|
||||||
|
val = readl(dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
|
||||||
|
if (val & WDOG_CONTROL_REG_WDT_EN_MASK)
|
||||||
|
writel(WDOG_COUNTER_RESTART_KICK_VALUE, dw_wdt.regs +
|
||||||
|
WDOG_COUNTER_RESTART_REG_OFFSET);
|
||||||
|
else
|
||||||
|
writel(WDOG_CONTROL_REG_WDT_EN_MASK,
|
||||||
|
dw_wdt.regs + WDOG_CONTROL_REG_OFFSET);
|
||||||
|
|
||||||
|
/* wait for reset to assert... */
|
||||||
|
mdelay(500);
|
||||||
|
|
||||||
|
return NOTIFY_DONE;
|
||||||
|
}
|
||||||
|
|
||||||
static void dw_wdt_ping(unsigned long data)
|
static void dw_wdt_ping(unsigned long data)
|
||||||
{
|
{
|
||||||
if (time_before(jiffies, dw_wdt.next_heartbeat) ||
|
if (time_before(jiffies, dw_wdt.next_heartbeat) ||
|
||||||
@ -316,6 +340,12 @@ static int dw_wdt_drv_probe(struct platform_device *pdev)
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto out_disable_clk;
|
goto out_disable_clk;
|
||||||
|
|
||||||
|
dw_wdt.restart_handler.notifier_call = dw_wdt_restart_handle;
|
||||||
|
dw_wdt.restart_handler.priority = 128;
|
||||||
|
ret = register_restart_handler(&dw_wdt.restart_handler);
|
||||||
|
if (ret)
|
||||||
|
pr_warn("cannot register restart handler\n");
|
||||||
|
|
||||||
dw_wdt_set_next_heartbeat();
|
dw_wdt_set_next_heartbeat();
|
||||||
setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
|
setup_timer(&dw_wdt.timer, dw_wdt_ping, 0);
|
||||||
mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
|
mod_timer(&dw_wdt.timer, jiffies + WDT_TIMEOUT);
|
||||||
@ -330,6 +360,8 @@ out_disable_clk:
|
|||||||
|
|
||||||
static int dw_wdt_drv_remove(struct platform_device *pdev)
|
static int dw_wdt_drv_remove(struct platform_device *pdev)
|
||||||
{
|
{
|
||||||
|
unregister_restart_handler(&dw_wdt.restart_handler);
|
||||||
|
|
||||||
misc_deregister(&dw_wdt_miscdev);
|
misc_deregister(&dw_wdt_miscdev);
|
||||||
|
|
||||||
clk_disable_unprepare(dw_wdt.clk);
|
clk_disable_unprepare(dw_wdt.clk);
|
||||||
|
Loading…
Reference in New Issue
Block a user