s390/watchdog: add support for LPAR operation (diag288)

Add the LPAR variant of the diag 288 watchdog to the driver.
The only available action on timeout for LPAR is a PSW restart.

Signed-off-by: Philipp Hachtmann <phacht@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
This commit is contained in:
Philipp Hachtmann 2014-06-05 11:02:36 +02:00 committed by Martin Schwidefsky
parent f7a94db4e9
commit 646f919e93
2 changed files with 35 additions and 4 deletions

View File

@ -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.

View File

@ -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;
}