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 provide a virtual watchdog timer to their guest that cause a
user define Control Program command to be executed after a user define Control Program command to be executed after a
timeout. timeout.
LPAR provides a very similar interface. This driver handles
both.
To compile this driver as a module, choose M here. The module To compile this driver as a module, choose M here. The module
will be called vmwatchdog. 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 * Under z/VM, expiration of the watchdog will send a "system restart" command
* to CP. * 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 * Copyright IBM Corp. 2004, 2013
* Author(s): Arnd Bergmann (arndb@de.ibm.com) * Author(s): Arnd Bergmann (arndb@de.ibm.com)
@ -41,6 +46,9 @@
#define WDT_FUNC_CANCEL 2 #define WDT_FUNC_CANCEL 2
#define WDT_FUNC_CONCEAL 0x80000000 #define WDT_FUNC_CONCEAL 0x80000000
/* Action codes for LPAR watchdog */
#define LPARWDT_RESTART 0
static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD; static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD;
static bool conceal_on; static bool conceal_on;
static bool nowayout_info = WATCHDOG_NOWAYOUT; 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); 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) static int wdt_start(struct watchdog_device *dev)
{ {
char *ebc_cmd; char *ebc_cmd;
@ -113,6 +127,11 @@ static int wdt_start(struct watchdog_device *dev)
kfree(ebc_cmd); kfree(ebc_cmd);
} }
if (MACHINE_IS_LPAR) {
ret = __diag288_lpar(WDT_FUNC_INIT,
dev->timeout, LPARWDT_RESTART);
}
if (ret) { if (ret) {
pr_err("The watchdog cannot be activated\n"); pr_err("The watchdog cannot be activated\n");
return ret; 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 * 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) func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL)
: WDT_FUNC_INIT; : WDT_FUNC_INIT;
@ -159,6 +179,9 @@ static int wdt_ping(struct watchdog_device *dev)
kfree(ebc_cmd); kfree(ebc_cmd);
} }
if (MACHINE_IS_LPAR)
ret = __diag288_lpar(WDT_FUNC_CHANGE, dev->timeout, 0);
if (ret) if (ret)
pr_err("The watchdog timer cannot be started or reset\n"); pr_err("The watchdog timer cannot be started or reset\n");
return ret; return ret;
@ -256,12 +279,18 @@ static int __init diag288_init(void)
pr_err("The watchdog cannot be initialized\n"); pr_err("The watchdog cannot be initialized\n");
return -EINVAL; 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 { } else {
pr_err("Linux runs in an environment that does not support the diag288 watchdog\n"); pr_err("Linux runs in an environment that does not support the diag288 watchdog\n");
return -ENODEV; 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"); pr_err("The watchdog cannot be deactivated\n");
return -EINVAL; return -EINVAL;
} }