summaryrefslogtreecommitdiffstats
path: root/drivers/watchdog
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2023-02-21 15:09:17 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2023-02-21 15:09:17 -0800
commitbcf5470eb4a13e5670fefb21525b43ef385c6fc6 (patch)
tree33395b005d3642873f385a628b7b7385608739d1 /drivers/watchdog
parent877934769e5b91798d304d4641647900ee614ce8 (diff)
parent6472a2dcc4274452bb46fb5a0d968a1c1ed772ee (diff)
downloadlinux-stable-bcf5470eb4a13e5670fefb21525b43ef385c6fc6.tar.gz
linux-stable-bcf5470eb4a13e5670fefb21525b43ef385c6fc6.tar.bz2
linux-stable-bcf5470eb4a13e5670fefb21525b43ef385c6fc6.zip
Merge tag 's390-6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux
Pull s390 updates from Heiko Carstens: - Large cleanup of the con3270/tty3270 driver. Among others this fixes: - Background Color Support - ASCII Line Character Support - VT100 Support - Geometries other than 80x24 - Cleanup and improve cmpxchg() code. Also add cmpxchg_user_key() to uaccess functions, which will be used by KVM to access KVM guest memory with a specific storage key - Add support for user space events counting to CPUMF - Cleanup the vfio/ccw code, which also allows now to properly support 2K Format-2 IDALs - Move kernel page table allocation and initialization to decompressor, which finally allows to enter the kernel with dynamic address translation enabled. This in turn allows to get rid of code with special handling in the kernel, which has to distinguish if DAT is on or off - Replace kretprobe with rethook - Various improvements to vfio/ap queue resets: - Use TAPQ to verify completion of a reset in progress rather than multiple invocations of ZAPQ. - Check TAPQ response codes when verifying successful completion of ZAPQ. - Fix erroneous handling of some error response codes. - Increase the maximum amount of time to wait for successful completion of ZAPQ - Rework system call wrappers to get rid of alias functions, which were only left on s390 - Cleanup diag288_wdt watchdog driver. It has been agreed on with Guenter Roeck that this goes upstream via the s390 tree - Add missing loadparm parameter handling for list-directed ECKD ipl/reipl - Various improvements to memory detection code - Remove arch_cpu_idle_time() since the current implementation is broken, and allows user space observable accounted idle times which can temporarily decrease - Add Reset DAT-Protection support: (only) allow to change PTEs from RO to RW with a new RDP instruction. Unlike the currently used IPTE instruction, this does not necessarily guarantee that TLBs of all CPUs are synchronously flushed; and that remote CPUs can see spurious protection faults. The overall improvement for not requiring an all CPU synchronization, like it is required with IPTE, should be beneficial - Fix KFENCE page fault reporting - Smaller cleanups and improvement all over the place * tag 's390-6.3-1' of git://git.kernel.org/pub/scm/linux/kernel/git/s390/linux: (182 commits) s390/irq,idle: simplify idle check s390/processor: add test_and_set_cpu_flag() and test_and_clear_cpu_flag() s390/processor: let cpu helper functions return boolean values s390/kfence: fix page fault reporting s390/zcrypt: introduce ctfm field in struct CPRBX s390: remove confusing comment from uapi types header file vfio/ccw: remove WARN_ON during shutdown s390/entry: remove toolchain dependent micro-optimization s390/mem_detect: do not truncate online memory ranges info s390/vx: remove __uint128_t type from __vector128 struct again s390/mm: add support for RDP (Reset DAT-Protection) s390/mm: define private VM_FAULT_* reasons from top bits Documentation: s390: correct spelling s390/ap: fix status returned by ap_qact() s390/ap: fix status returned by ap_aqic() s390: vfio-ap: tighten the NIB validity check Revert "s390/mem_detect: do not update output parameters on failure" s390/idle: remove arch_cpu_idle_time() and corresponding code s390/vx: use simple assignments to access __vector128 members s390/vx: add 64 and 128 bit members to __vector128 struct ...
Diffstat (limited to 'drivers/watchdog')
-rw-r--r--drivers/watchdog/diag288_wdt.c162
1 files changed, 37 insertions, 125 deletions
diff --git a/drivers/watchdog/diag288_wdt.c b/drivers/watchdog/diag288_wdt.c
index 6ca5d9515d85..4631d0a3866a 100644
--- a/drivers/watchdog/diag288_wdt.c
+++ b/drivers/watchdog/diag288_wdt.c
@@ -27,7 +27,6 @@
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/watchdog.h>
-#include <linux/suspend.h>
#include <asm/ebcdic.h>
#include <asm/diag.h>
#include <linux/io.h>
@@ -70,77 +69,58 @@ MODULE_PARM_DESC(nowayout, "Watchdog cannot be stopped once started (default = C
MODULE_ALIAS("vmwatchdog");
-static int __diag288(unsigned int func, unsigned int timeout,
- unsigned long action, unsigned int len)
+static char *cmd_buf;
+
+static int diag288(unsigned int func, unsigned int timeout,
+ unsigned long action, unsigned int len)
{
- register unsigned long __func asm("2") = func;
- register unsigned long __timeout asm("3") = timeout;
- register unsigned long __action asm("4") = action;
- register unsigned long __len asm("5") = len;
+ union register_pair r1 = { .even = func, .odd = timeout, };
+ union register_pair r3 = { .even = action, .odd = len, };
int err;
+ diag_stat_inc(DIAG_STAT_X288);
+
err = -EINVAL;
asm volatile(
- " diag %1, %3, 0x288\n"
- "0: la %0, 0\n"
+ " diag %[r1],%[r3],0x288\n"
+ "0: la %[err],0\n"
"1:\n"
EX_TABLE(0b, 1b)
- : "+d" (err) : "d"(__func), "d"(__timeout),
- "d"(__action), "d"(__len) : "1", "cc", "memory");
+ : [err] "+d" (err)
+ : [r1] "d" (r1.pair), [r3] "d" (r3.pair)
+ : "cc", "memory");
return err;
}
-static int __diag288_vm(unsigned int func, unsigned int timeout,
- char *cmd, size_t len)
+static int diag288_str(unsigned int func, unsigned int timeout, char *cmd)
{
- diag_stat_inc(DIAG_STAT_X288);
- return __diag288(func, timeout, virt_to_phys(cmd), len);
-}
+ ssize_t len;
-static int __diag288_lpar(unsigned int func, unsigned int timeout,
- unsigned long action)
-{
- diag_stat_inc(DIAG_STAT_X288);
- return __diag288(func, timeout, action, 0);
-}
-
-static unsigned long wdt_status;
+ len = strscpy(cmd_buf, cmd, MAX_CMDLEN);
+ if (len < 0)
+ return len;
+ ASCEBC(cmd_buf, MAX_CMDLEN);
+ EBC_TOUPPER(cmd_buf, MAX_CMDLEN);
-#define DIAG_WDOG_BUSY 0
+ return diag288(func, timeout, virt_to_phys(cmd_buf), len);
+}
static int wdt_start(struct watchdog_device *dev)
{
- char *ebc_cmd;
- size_t len;
int ret;
unsigned int func;
- if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status))
- return -EBUSY;
-
if (MACHINE_IS_VM) {
- ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
- if (!ebc_cmd) {
- clear_bit(DIAG_WDOG_BUSY, &wdt_status);
- return -ENOMEM;
- }
- len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN);
- ASCEBC(ebc_cmd, MAX_CMDLEN);
- EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
-
func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL)
: WDT_FUNC_INIT;
- ret = __diag288_vm(func, dev->timeout, ebc_cmd, len);
+ ret = diag288_str(func, dev->timeout, wdt_cmd);
WARN_ON(ret != 0);
- kfree(ebc_cmd);
} else {
- ret = __diag288_lpar(WDT_FUNC_INIT,
- dev->timeout, LPARWDT_RESTART);
+ ret = diag288(WDT_FUNC_INIT, dev->timeout, LPARWDT_RESTART, 0);
}
if (ret) {
pr_err("The watchdog cannot be activated\n");
- clear_bit(DIAG_WDOG_BUSY, &wdt_status);
return ret;
}
return 0;
@@ -148,31 +128,15 @@ static int wdt_start(struct watchdog_device *dev)
static int wdt_stop(struct watchdog_device *dev)
{
- int ret;
-
- diag_stat_inc(DIAG_STAT_X288);
- ret = __diag288(WDT_FUNC_CANCEL, 0, 0, 0);
-
- clear_bit(DIAG_WDOG_BUSY, &wdt_status);
-
- return ret;
+ return diag288(WDT_FUNC_CANCEL, 0, 0, 0);
}
static int wdt_ping(struct watchdog_device *dev)
{
- char *ebc_cmd;
- size_t len;
int ret;
unsigned int func;
if (MACHINE_IS_VM) {
- ebc_cmd = kmalloc(MAX_CMDLEN, GFP_KERNEL);
- if (!ebc_cmd)
- return -ENOMEM;
- len = strlcpy(ebc_cmd, wdt_cmd, MAX_CMDLEN);
- ASCEBC(ebc_cmd, MAX_CMDLEN);
- EBC_TOUPPER(ebc_cmd, MAX_CMDLEN);
-
/*
* It seems to be ok to z/VM to use the init function to
* retrigger the watchdog. On LPAR WDT_FUNC_CHANGE must
@@ -181,11 +145,10 @@ static int wdt_ping(struct watchdog_device *dev)
func = conceal_on ? (WDT_FUNC_INIT | WDT_FUNC_CONCEAL)
: WDT_FUNC_INIT;
- ret = __diag288_vm(func, dev->timeout, ebc_cmd, len);
+ ret = diag288_str(func, dev->timeout, wdt_cmd);
WARN_ON(ret != 0);
- kfree(ebc_cmd);
} else {
- ret = __diag288_lpar(WDT_FUNC_CHANGE, dev->timeout, 0);
+ ret = diag288(WDT_FUNC_CHANGE, dev->timeout, 0, 0);
}
if (ret)
@@ -223,96 +186,45 @@ static struct watchdog_device wdt_dev = {
.max_timeout = MAX_INTERVAL,
};
-/*
- * It makes no sense to go into suspend while the watchdog is running.
- * Depending on the memory size, the watchdog might trigger, while we
- * are still saving the memory.
- */
-static int wdt_suspend(void)
-{
- if (test_and_set_bit(DIAG_WDOG_BUSY, &wdt_status)) {
- pr_err("Linux cannot be suspended while the watchdog is in use\n");
- return notifier_from_errno(-EBUSY);
- }
- return NOTIFY_DONE;
-}
-
-static int wdt_resume(void)
-{
- clear_bit(DIAG_WDOG_BUSY, &wdt_status);
- return NOTIFY_DONE;
-}
-
-static int wdt_power_event(struct notifier_block *this, unsigned long event,
- void *ptr)
-{
- switch (event) {
- case PM_POST_HIBERNATION:
- case PM_POST_SUSPEND:
- return wdt_resume();
- case PM_HIBERNATION_PREPARE:
- case PM_SUSPEND_PREPARE:
- return wdt_suspend();
- default:
- return NOTIFY_DONE;
- }
-}
-
-static struct notifier_block wdt_power_notifier = {
- .notifier_call = wdt_power_event,
-};
-
static int __init diag288_init(void)
{
int ret;
- char ebc_begin[] = {
- 194, 197, 199, 201, 213
- };
- char *ebc_cmd;
watchdog_set_nowayout(&wdt_dev, nowayout_info);
if (MACHINE_IS_VM) {
- ebc_cmd = kmalloc(sizeof(ebc_begin), GFP_KERNEL);
- if (!ebc_cmd) {
+ cmd_buf = kmalloc(MAX_CMDLEN, GFP_KERNEL);
+ if (!cmd_buf) {
pr_err("The watchdog cannot be initialized\n");
return -ENOMEM;
}
- memcpy(ebc_cmd, ebc_begin, sizeof(ebc_begin));
- ret = __diag288_vm(WDT_FUNC_INIT, 15,
- ebc_cmd, sizeof(ebc_begin));
- kfree(ebc_cmd);
+
+ ret = diag288_str(WDT_FUNC_INIT, MIN_INTERVAL, "BEGIN");
if (ret != 0) {
pr_err("The watchdog cannot be initialized\n");
+ kfree(cmd_buf);
return -EINVAL;
}
} else {
- if (__diag288_lpar(WDT_FUNC_INIT, 30, LPARWDT_RESTART)) {
+ if (diag288(WDT_FUNC_INIT, WDT_DEFAULT_TIMEOUT,
+ LPARWDT_RESTART, 0)) {
pr_err("The watchdog cannot be initialized\n");
return -EINVAL;
}
}
- if (__diag288_lpar(WDT_FUNC_CANCEL, 0, 0)) {
+ if (diag288(WDT_FUNC_CANCEL, 0, 0, 0)) {
pr_err("The watchdog cannot be deactivated\n");
return -EINVAL;
}
- ret = register_pm_notifier(&wdt_power_notifier);
- if (ret)
- return ret;
-
- ret = watchdog_register_device(&wdt_dev);
- if (ret)
- unregister_pm_notifier(&wdt_power_notifier);
-
- return ret;
+ return watchdog_register_device(&wdt_dev);
}
static void __exit diag288_exit(void)
{
watchdog_unregister_device(&wdt_dev);
- unregister_pm_notifier(&wdt_power_notifier);
+ kfree(cmd_buf);
}
module_init(diag288_init);