diff options
-rw-r--r-- | drivers/watchdog/Kconfig | 2 | ||||
-rw-r--r-- | drivers/watchdog/diag288_wdt.c | 37 |
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; } |