summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/watchdog/Kconfig2
-rw-r--r--drivers/watchdog/diag288_wdt.c37
2 files changed, 35 insertions, 4 deletions
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index daf944148b7a..ac1f1def1f11 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -1304,6 +1304,8 @@ config DIAG288_WATCHDOG
provide a virtual watchdog timer to their guest that cause a
user define Control Program command to be executed after a
timeout.
+ LPAR provides a very similar interface. This driver handles
+ both.
To compile this driver as a module, choose M here. The module
will be called vmwatchdog.
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c
index d406711d770e..429494b6c822 100644
--- a/drivers/watchdog/diag288_wdt.c
+++ b/drivers/watchdog/diag288_wdt.c
@@ -1,10 +1,15 @@
/*
- * Watchdog driver for z/VM using the diag 288 interface.
+ * Watchdog driver for z/VM and LPAR using the diag 288 interface.
*
* Under z/VM, expiration of the watchdog will send a "system restart" command
* to CP.
*
- * The command can be altered using the module parameter "cmd".
+ * The command can be altered using the module parameter "cmd". This is
+ * not recommended because it's only supported on z/VM but not whith LPAR.
+ *
+ * On LPAR, the watchdog will always trigger a system restart. the module
+ * paramter cmd is meaningless here.
+ *
*
* Copyright IBM Corp. 2004, 2013
* Author(s): Arnd Bergmann (arndb@de.ibm.com)
@@ -41,6 +46,9 @@
#define WDT_FUNC_CANCEL 2
#define WDT_FUNC_CONCEAL 0x80000000
+/* Action codes for LPAR watchdog */
+#define LPARWDT_RESTART 0
+
static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD;
static bool conceal_on;
static bool nowayout_info = WATCHDOG_NOWAYOUT;
@@ -89,6 +97,12 @@ static int __diag288_vm(unsigned int func, unsigned int timeout,
return __diag288(func, timeout, virt_to_phys(cmd), len);
}
+static int __diag288_lpar(unsigned int func, unsigned int timeout,
+ unsigned long action)
+{
+ return __diag288(func, timeout, action, 0);
+}
+
static int wdt_start(struct watchdog_device *dev)
{
char *ebc_cmd;
@@ -113,6 +127,11 @@ static int wdt_start(struct watchdog_device *dev)
kfree(ebc_cmd);
}
+ if (MACHINE_IS_LPAR) {
+ ret = __diag288_lpar(WDT_FUNC_INIT,
+ dev->timeout, LPARWDT_RESTART);
+ }
+
if (ret) {
pr_err("The watchdog cannot be activated\n");
return ret;
@@ -149,7 +168,8 @@ static int wdt_ping(struct watchdog_device *dev)
/*
* It seems to be ok to z/VM to use the init function to
- * retrigger the watchdog.
+ * retrigger the watchdog. On LPAR WDT_FUNC_CHANGE must
+ * be used when the watchdog is running.
*/
func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL)
: WDT_FUNC_INIT;
@@ -159,6 +179,9 @@ static int wdt_ping(struct watchdog_device *dev)
kfree(ebc_cmd);
}
+ if (MACHINE_IS_LPAR)
+ ret = __diag288_lpar(WDT_FUNC_CHANGE, dev->timeout, 0);
+
if (ret)
pr_err("The watchdog timer cannot be started or reset\n");
return ret;
@@ -256,12 +279,18 @@ static int __init diag288_init(void)
pr_err("The watchdog cannot be initialized\n");
return -EINVAL;
}
+ } else if (MACHINE_IS_LPAR) {
+ pr_info("The watchdog device driver detected an LPAR environment\n");
+ if (__diag288_lpar(WDT_FUNC_INIT, 30, LPARWDT_RESTART)) {
+ pr_err("The watchdog cannot be initialized\n");
+ return -EINVAL;
+ }
} else {
pr_err("Linux runs in an environment that does not support the diag288 watchdog\n");
return -ENODEV;
}
- if (__diag288_vm(WDT_FUNC_CANCEL, 0, NULL, 0)) {
+ if (__diag288_lpar(WDT_FUNC_CANCEL, 0, 0)) {
pr_err("The watchdog cannot be deactivated\n");
return -EINVAL;
}