mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:44:45 +01:00
watchdog: diag288_wdt: Implement module autoload
The s390 specific diag288_wdt watchdog driver makes use of the virtual watchdog timer, which is available in most machine configurations. If executing the diagnose instruction with subcode 0x288 results in an exception the watchdog timer is not available, otherwise it is available. In order to allow module autoload of the diag288_wdt module, move the detection of the virtual watchdog timer to early boot code, and provide its availability as a cpu feature. This allows to make use of module_cpu_feature_match() to automatically load the module iff the virtual watchdog timer is available. Suggested-by: Marc Hartmayer <mhartmay@linux.ibm.com> Tested-by: Mete Durlu <meted@linux.ibm.com> Acked-by: Guenter Roeck <linux@roeck-us.net> Link: https://lore.kernel.org/r/20250410095036.1525057-1-hca@linux.ibm.com Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
This commit is contained in:
parent
1468d6b1d3
commit
1c745df519
6 changed files with 68 additions and 50 deletions
|
|
@ -6,6 +6,7 @@
|
|||
#include <asm/boot_data.h>
|
||||
#include <asm/extmem.h>
|
||||
#include <asm/sections.h>
|
||||
#include <asm/diag288.h>
|
||||
#include <asm/maccess.h>
|
||||
#include <asm/machine.h>
|
||||
#include <asm/sysinfo.h>
|
||||
|
|
@ -71,6 +72,20 @@ static void detect_machine_type(void)
|
|||
set_machine_feature(MFEATURE_VM);
|
||||
}
|
||||
|
||||
static void detect_diag288(void)
|
||||
{
|
||||
/* "BEGIN" in EBCDIC character set */
|
||||
static const char cmd[] = "\xc2\xc5\xc7\xc9\xd5";
|
||||
unsigned long action, len;
|
||||
|
||||
action = machine_is_vm() ? (unsigned long)cmd : LPARWDT_RESTART;
|
||||
len = machine_is_vm() ? sizeof(cmd) : 0;
|
||||
if (__diag288(WDT_FUNC_INIT, MIN_INTERVAL, action, len))
|
||||
return;
|
||||
__diag288(WDT_FUNC_CANCEL, 0, 0, 0);
|
||||
set_machine_feature(MFEATURE_DIAG288);
|
||||
}
|
||||
|
||||
static void detect_diag9c(void)
|
||||
{
|
||||
unsigned int cpu;
|
||||
|
|
@ -519,6 +534,8 @@ void startup_kernel(void)
|
|||
detect_facilities();
|
||||
detect_diag9c();
|
||||
detect_machine_type();
|
||||
/* detect_diag288() needs machine type */
|
||||
detect_diag288();
|
||||
cmma_init();
|
||||
sanitize_prot_virt_host();
|
||||
max_physmem_end = detect_max_physmem_end();
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ enum {
|
|||
S390_CPU_FEATURE_MSA,
|
||||
S390_CPU_FEATURE_VXRS,
|
||||
S390_CPU_FEATURE_UV,
|
||||
S390_CPU_FEATURE_D288,
|
||||
MAX_CPU_FEATURES
|
||||
};
|
||||
|
||||
|
|
|
|||
41
arch/s390/include/asm/diag288.h
Normal file
41
arch/s390/include/asm/diag288.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
|
||||
#ifndef _ASM_S390_DIAG288_H
|
||||
#define _ASM_S390_DIAG288_H
|
||||
|
||||
#include <asm/asm-extable.h>
|
||||
#include <asm/types.h>
|
||||
|
||||
#define MIN_INTERVAL 15 /* Minimal time supported by diag288 */
|
||||
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
|
||||
|
||||
#define WDT_DEFAULT_TIMEOUT 30
|
||||
|
||||
/* Function codes - init, change, cancel */
|
||||
#define WDT_FUNC_INIT 0
|
||||
#define WDT_FUNC_CHANGE 1
|
||||
#define WDT_FUNC_CANCEL 2
|
||||
#define WDT_FUNC_CONCEAL 0x80000000
|
||||
|
||||
/* Action codes for LPAR watchdog */
|
||||
#define LPARWDT_RESTART 0
|
||||
|
||||
static inline int __diag288(unsigned int func, unsigned int timeout,
|
||||
unsigned long action, unsigned int len)
|
||||
{
|
||||
union register_pair r1 = { .even = func, .odd = timeout, };
|
||||
union register_pair r3 = { .even = action, .odd = len, };
|
||||
int rc = -EINVAL;
|
||||
|
||||
asm volatile(
|
||||
" diag %[r1],%[r3],0x288\n"
|
||||
"0: lhi %[rc],0\n"
|
||||
"1:"
|
||||
EX_TABLE(0b, 1b)
|
||||
: [rc] "+d" (rc)
|
||||
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
|
||||
: "cc", "memory");
|
||||
return rc;
|
||||
}
|
||||
|
||||
#endif /* _ASM_S390_DIAG288_H */
|
||||
|
|
@ -18,6 +18,7 @@
|
|||
#define MFEATURE_VM 7
|
||||
#define MFEATURE_KVM 8
|
||||
#define MFEATURE_LPAR 9
|
||||
#define MFEATURE_DIAG288 10
|
||||
|
||||
#ifndef __ASSEMBLY__
|
||||
|
||||
|
|
|
|||
|
|
@ -5,11 +5,13 @@
|
|||
|
||||
#include <linux/cpufeature.h>
|
||||
#include <linux/bug.h>
|
||||
#include <asm/machine.h>
|
||||
#include <asm/elf.h>
|
||||
|
||||
enum {
|
||||
TYPE_HWCAP,
|
||||
TYPE_FACILITY,
|
||||
TYPE_MACHINE,
|
||||
};
|
||||
|
||||
struct s390_cpu_feature {
|
||||
|
|
@ -21,6 +23,7 @@ static struct s390_cpu_feature s390_cpu_features[MAX_CPU_FEATURES] = {
|
|||
[S390_CPU_FEATURE_MSA] = {.type = TYPE_HWCAP, .num = HWCAP_NR_MSA},
|
||||
[S390_CPU_FEATURE_VXRS] = {.type = TYPE_HWCAP, .num = HWCAP_NR_VXRS},
|
||||
[S390_CPU_FEATURE_UV] = {.type = TYPE_FACILITY, .num = 158},
|
||||
[S390_CPU_FEATURE_D288] = {.type = TYPE_MACHINE, .num = MFEATURE_DIAG288},
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
@ -38,6 +41,8 @@ int cpu_have_feature(unsigned int num)
|
|||
return !!(elf_hwcap & BIT(feature->num));
|
||||
case TYPE_FACILITY:
|
||||
return test_facility(feature->num);
|
||||
case TYPE_MACHINE:
|
||||
return test_machine_feature(feature->num);
|
||||
default:
|
||||
WARN_ON_ONCE(1);
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -29,26 +29,13 @@
|
|||
#include <linux/watchdog.h>
|
||||
#include <asm/machine.h>
|
||||
#include <asm/ebcdic.h>
|
||||
#include <asm/diag288.h>
|
||||
#include <asm/diag.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#define MAX_CMDLEN 240
|
||||
#define DEFAULT_CMD "SYSTEM RESTART"
|
||||
|
||||
#define MIN_INTERVAL 15 /* Minimal time supported by diag88 */
|
||||
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
|
||||
|
||||
#define WDT_DEFAULT_TIMEOUT 30
|
||||
|
||||
/* Function codes - init, change, cancel */
|
||||
#define WDT_FUNC_INIT 0
|
||||
#define WDT_FUNC_CHANGE 1
|
||||
#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;
|
||||
|
|
@ -75,22 +62,8 @@ static char *cmd_buf;
|
|||
static int diag288(unsigned int func, unsigned int timeout,
|
||||
unsigned long action, unsigned int 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 %[r1],%[r3],0x288\n"
|
||||
"0: la %[err],0\n"
|
||||
"1:\n"
|
||||
EX_TABLE(0b, 1b)
|
||||
: [err] "+d" (err)
|
||||
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
|
||||
: "cc", "memory");
|
||||
return err;
|
||||
return __diag288(func, timeout, action, len);
|
||||
}
|
||||
|
||||
static int diag288_str(unsigned int func, unsigned int timeout, char *cmd)
|
||||
|
|
@ -189,8 +162,6 @@ static struct watchdog_device wdt_dev = {
|
|||
|
||||
static int __init diag288_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
watchdog_set_nowayout(&wdt_dev, nowayout_info);
|
||||
|
||||
if (machine_is_vm()) {
|
||||
|
|
@ -199,24 +170,6 @@ static int __init diag288_init(void)
|
|||
pr_err("The watchdog cannot be initialized\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
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(WDT_FUNC_INIT, WDT_DEFAULT_TIMEOUT,
|
||||
LPARWDT_RESTART, 0)) {
|
||||
pr_err("The watchdog cannot be initialized\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
if (diag288(WDT_FUNC_CANCEL, 0, 0, 0)) {
|
||||
pr_err("The watchdog cannot be deactivated\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return watchdog_register_device(&wdt_dev);
|
||||
|
|
@ -228,5 +181,5 @@ static void __exit diag288_exit(void)
|
|||
kfree(cmd_buf);
|
||||
}
|
||||
|
||||
module_init(diag288_init);
|
||||
module_cpu_feature_match(S390_CPU_FEATURE_D288, diag288_init);
|
||||
module_exit(diag288_exit);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue