提交 4245f447 编写于 作者: W Wang Wensheng 提交者: Yang Yingliang

sbsa_gwdt: Introduce a panic notifier

hulk inclusion
category: feature
bugzilla: NA
CVE: NA

When the kernel panic we reset the timeout to pretimeout, then after
pretimeout seconds the sbsa_gwdt reset the system.

The pretimeout to be set is configured via the watchdog-core, but the
meaning is different from that of the watchdog-core. The pretimeout here
defines the new timeout for the sbsa_gwdt after panic while that of the
watchdog-core is meaningful where the WDT would raise an interrupt
before timeout and it defines the length of that period. That period of
sbsa_gwdt cannot be changed separately so the redefination here doesn't
make trouble.

The pretimeout here follow the same limit of that of watchdog-core that
the pretimeout shall be smaller than timeout, since we prefer that the
sbsa_gwdt would reset the system sooner on panic.

We add a new kconfig ARM_SBSA_WATCHDOG_PANIC_NOTIFIER to control the
feature. Set action to 2 to enable the notifier.
Signed-off-by: NWang Wensheng <wangwensheng4@huawei.com>
Reviewed-by: NXiongfeng Wang <wangxiongfeng2@huawei.com>
Reviewed-by: NDing Tianhong <dingtianhong@huawei.com>
Signed-off-by: NYang Yingliang <yangyingliang@huawei.com>
上级 eb773093
...@@ -273,6 +273,14 @@ config ARM_SBSA_WATCHDOG ...@@ -273,6 +273,14 @@ config ARM_SBSA_WATCHDOG
To compile this driver as module, choose M here: The module To compile this driver as module, choose M here: The module
will be called sbsa_gwdt. will be called sbsa_gwdt.
config ARM_SBSA_WATCHDOG_PANIC_NOTIFIER
bool "Reset the WDT Timeout on Panic"
depends on ASCEND_FEATURES
depends on ARM_SBSA_WATCHDOG
help
This registers a panic notifier that reset the timeout of watchdog to
pretimeout set by user before.
config ASM9260_WATCHDOG config ASM9260_WATCHDOG
tristate "Alphascale ASM9260 watchdog" tristate "Alphascale ASM9260 watchdog"
depends on MACH_ASM9260 || COMPILE_TEST depends on MACH_ASM9260 || COMPILE_TEST
......
...@@ -108,12 +108,13 @@ MODULE_PARM_DESC(timeout, ...@@ -108,12 +108,13 @@ MODULE_PARM_DESC(timeout,
* action refers to action taken when watchdog gets WS0 * action refers to action taken when watchdog gets WS0
* 0 = skip * 0 = skip
* 1 = panic * 1 = panic
* 2 = panic and reset timeout (need to enable CONFIG_ARM_SBSA_WATCHDOG_PANIC_NOTIFIER)
* defaults to skip (0) * defaults to skip (0)
*/ */
static int action; static int action;
module_param(action, int, 0); module_param(action, int, 0);
MODULE_PARM_DESC(action, "after watchdog gets WS0 interrupt, do: " MODULE_PARM_DESC(action, "after watchdog gets WS0 interrupt, do: "
"0 = skip(*) 1 = panic"); "0 = skip(*) 1 = panic 2 = panic_notifier");
static bool nowayout = WATCHDOG_NOWAYOUT; static bool nowayout = WATCHDOG_NOWAYOUT;
module_param(nowayout, bool, S_IRUGO); module_param(nowayout, bool, S_IRUGO);
...@@ -130,6 +131,11 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd, ...@@ -130,6 +131,11 @@ static int sbsa_gwdt_set_timeout(struct watchdog_device *wdd,
struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd); struct sbsa_gwdt *gwdt = watchdog_get_drvdata(wdd);
wdd->timeout = timeout; wdd->timeout = timeout;
#ifdef CONFIG_ARM_SBSA_WATCHDOG_PANIC_NOTIFIER
/* Disable pretimeout if it doesn't fit the new timeout */
if (action == 2 && wdd->pretimeout >= wdd->timeout)
wdd->pretimeout = 0;
#endif
if (action) if (action)
writel(gwdt->clk * timeout, writel(gwdt->clk * timeout,
...@@ -208,7 +214,7 @@ static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id) ...@@ -208,7 +214,7 @@ static irqreturn_t sbsa_gwdt_interrupt(int irq, void *dev_id)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static const struct watchdog_info sbsa_gwdt_info = { static struct watchdog_info sbsa_gwdt_info = {
.identity = WATCHDOG_NAME, .identity = WATCHDOG_NAME,
.options = WDIOF_SETTIMEOUT | .options = WDIOF_SETTIMEOUT |
WDIOF_KEEPALIVEPING | WDIOF_KEEPALIVEPING |
...@@ -225,6 +231,44 @@ static const struct watchdog_ops sbsa_gwdt_ops = { ...@@ -225,6 +231,44 @@ static const struct watchdog_ops sbsa_gwdt_ops = {
.get_timeleft = sbsa_gwdt_get_timeleft, .get_timeleft = sbsa_gwdt_get_timeleft,
}; };
#ifdef CONFIG_ARM_SBSA_WATCHDOG_PANIC_NOTIFIER
static struct sbsa_gwdt_notifier_s {
struct sbsa_gwdt *gwdt;
struct notifier_block panic_notifier;
} sbsa_gwdt_notifier;
static int gwdt_reset_timeout(struct notifier_block *self,
unsigned long v, void *p)
{
struct sbsa_gwdt *gwdt =
container_of(self, struct sbsa_gwdt_notifier_s,
panic_notifier)->gwdt;
unsigned int timeout = gwdt->wdd.pretimeout;
unsigned int div = 1U;
/*
* If the panic occurred after when WSO was raised, the gwdt would
* reset the board after WOR. If WS0 was not raised WOR * 2 would
* take before gwdt would reset the board.
*/
if (!(readl(gwdt->control_base + SBSA_GWDT_WCS) & SBSA_GWDT_WCS_WS0))
div = 2U;
writel(gwdt->clk * timeout / div, gwdt->control_base + SBSA_GWDT_WOR);
return 0;
}
static void sbsa_register_panic_notifier(struct sbsa_gwdt *gwdt)
{
sbsa_gwdt_notifier.gwdt = gwdt;
sbsa_gwdt_notifier.panic_notifier.notifier_call = gwdt_reset_timeout;
sbsa_gwdt_notifier.panic_notifier.priority = INT_MAX;
atomic_notifier_chain_register(&panic_notifier_list,
&sbsa_gwdt_notifier.panic_notifier);
}
#endif
static int sbsa_gwdt_probe(struct platform_device *pdev) static int sbsa_gwdt_probe(struct platform_device *pdev)
{ {
void __iomem *rf_base, *cf_base; void __iomem *rf_base, *cf_base;
...@@ -317,6 +361,20 @@ static int sbsa_gwdt_probe(struct platform_device *pdev) ...@@ -317,6 +361,20 @@ static int sbsa_gwdt_probe(struct platform_device *pdev)
if (ret) if (ret)
return ret; return ret;
#ifdef CONFIG_ARM_SBSA_WATCHDOG_PANIC_NOTIFIER
if (action == 2) {
/*
* Since pretimeout should be smaller than timeout we initialize
* pretimeout to timeout-1.
* Add WDIOF_PRETIMEOUT flags to enable user to configure it.
*/
gwdt->wdd.pretimeout = gwdt->wdd.timeout - 1;
sbsa_gwdt_info.options |= WDIOF_PRETIMEOUT;
sbsa_register_panic_notifier(gwdt);
}
#endif
dev_info(dev, "Initialized with %ds timeout @ %u Hz, action=%d.%s\n", dev_info(dev, "Initialized with %ds timeout @ %u Hz, action=%d.%s\n",
wdd->timeout, gwdt->clk, action, wdd->timeout, gwdt->clk, action,
status & SBSA_GWDT_WCS_EN ? " [enabled]" : ""); status & SBSA_GWDT_WCS_EN ? " [enabled]" : "");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册