Skip to content

Commit 1c745df

Browse files
committed
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>
1 parent 1468d6b commit 1c745df

6 files changed

Lines changed: 68 additions & 50 deletions

File tree

arch/s390/boot/startup.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <asm/boot_data.h>
77
#include <asm/extmem.h>
88
#include <asm/sections.h>
9+
#include <asm/diag288.h>
910
#include <asm/maccess.h>
1011
#include <asm/machine.h>
1112
#include <asm/sysinfo.h>
@@ -71,6 +72,20 @@ static void detect_machine_type(void)
7172
set_machine_feature(MFEATURE_VM);
7273
}
7374

75+
static void detect_diag288(void)
76+
{
77+
/* "BEGIN" in EBCDIC character set */
78+
static const char cmd[] = "\xc2\xc5\xc7\xc9\xd5";
79+
unsigned long action, len;
80+
81+
action = machine_is_vm() ? (unsigned long)cmd : LPARWDT_RESTART;
82+
len = machine_is_vm() ? sizeof(cmd) : 0;
83+
if (__diag288(WDT_FUNC_INIT, MIN_INTERVAL, action, len))
84+
return;
85+
__diag288(WDT_FUNC_CANCEL, 0, 0, 0);
86+
set_machine_feature(MFEATURE_DIAG288);
87+
}
88+
7489
static void detect_diag9c(void)
7590
{
7691
unsigned int cpu;
@@ -519,6 +534,8 @@ void startup_kernel(void)
519534
detect_facilities();
520535
detect_diag9c();
521536
detect_machine_type();
537+
/* detect_diag288() needs machine type */
538+
detect_diag288();
522539
cmma_init();
523540
sanitize_prot_virt_host();
524541
max_physmem_end = detect_max_physmem_end();

arch/s390/include/asm/cpufeature.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ enum {
1515
S390_CPU_FEATURE_MSA,
1616
S390_CPU_FEATURE_VXRS,
1717
S390_CPU_FEATURE_UV,
18+
S390_CPU_FEATURE_D288,
1819
MAX_CPU_FEATURES
1920
};
2021

arch/s390/include/asm/diag288.h

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
3+
#ifndef _ASM_S390_DIAG288_H
4+
#define _ASM_S390_DIAG288_H
5+
6+
#include <asm/asm-extable.h>
7+
#include <asm/types.h>
8+
9+
#define MIN_INTERVAL 15 /* Minimal time supported by diag288 */
10+
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
11+
12+
#define WDT_DEFAULT_TIMEOUT 30
13+
14+
/* Function codes - init, change, cancel */
15+
#define WDT_FUNC_INIT 0
16+
#define WDT_FUNC_CHANGE 1
17+
#define WDT_FUNC_CANCEL 2
18+
#define WDT_FUNC_CONCEAL 0x80000000
19+
20+
/* Action codes for LPAR watchdog */
21+
#define LPARWDT_RESTART 0
22+
23+
static inline int __diag288(unsigned int func, unsigned int timeout,
24+
unsigned long action, unsigned int len)
25+
{
26+
union register_pair r1 = { .even = func, .odd = timeout, };
27+
union register_pair r3 = { .even = action, .odd = len, };
28+
int rc = -EINVAL;
29+
30+
asm volatile(
31+
" diag %[r1],%[r3],0x288\n"
32+
"0: lhi %[rc],0\n"
33+
"1:"
34+
EX_TABLE(0b, 1b)
35+
: [rc] "+d" (rc)
36+
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
37+
: "cc", "memory");
38+
return rc;
39+
}
40+
41+
#endif /* _ASM_S390_DIAG288_H */

arch/s390/include/asm/machine.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#define MFEATURE_VM 7
1919
#define MFEATURE_KVM 8
2020
#define MFEATURE_LPAR 9
21+
#define MFEATURE_DIAG288 10
2122

2223
#ifndef __ASSEMBLY__
2324

arch/s390/kernel/cpufeature.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55

66
#include <linux/cpufeature.h>
77
#include <linux/bug.h>
8+
#include <asm/machine.h>
89
#include <asm/elf.h>
910

1011
enum {
1112
TYPE_HWCAP,
1213
TYPE_FACILITY,
14+
TYPE_MACHINE,
1315
};
1416

1517
struct s390_cpu_feature {
@@ -21,6 +23,7 @@ static struct s390_cpu_feature s390_cpu_features[MAX_CPU_FEATURES] = {
2123
[S390_CPU_FEATURE_MSA] = {.type = TYPE_HWCAP, .num = HWCAP_NR_MSA},
2224
[S390_CPU_FEATURE_VXRS] = {.type = TYPE_HWCAP, .num = HWCAP_NR_VXRS},
2325
[S390_CPU_FEATURE_UV] = {.type = TYPE_FACILITY, .num = 158},
26+
[S390_CPU_FEATURE_D288] = {.type = TYPE_MACHINE, .num = MFEATURE_DIAG288},
2427
};
2528

2629
/*
@@ -38,6 +41,8 @@ int cpu_have_feature(unsigned int num)
3841
return !!(elf_hwcap & BIT(feature->num));
3942
case TYPE_FACILITY:
4043
return test_facility(feature->num);
44+
case TYPE_MACHINE:
45+
return test_machine_feature(feature->num);
4146
default:
4247
WARN_ON_ONCE(1);
4348
return 0;

drivers/watchdog/diag288_wdt.c

Lines changed: 3 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -29,26 +29,13 @@
2929
#include <linux/watchdog.h>
3030
#include <asm/machine.h>
3131
#include <asm/ebcdic.h>
32+
#include <asm/diag288.h>
3233
#include <asm/diag.h>
3334
#include <linux/io.h>
3435

3536
#define MAX_CMDLEN 240
3637
#define DEFAULT_CMD "SYSTEM RESTART"
3738

38-
#define MIN_INTERVAL 15 /* Minimal time supported by diag88 */
39-
#define MAX_INTERVAL 3600 /* One hour should be enough - pure estimation */
40-
41-
#define WDT_DEFAULT_TIMEOUT 30
42-
43-
/* Function codes - init, change, cancel */
44-
#define WDT_FUNC_INIT 0
45-
#define WDT_FUNC_CHANGE 1
46-
#define WDT_FUNC_CANCEL 2
47-
#define WDT_FUNC_CONCEAL 0x80000000
48-
49-
/* Action codes for LPAR watchdog */
50-
#define LPARWDT_RESTART 0
51-
5239
static char wdt_cmd[MAX_CMDLEN] = DEFAULT_CMD;
5340
static bool conceal_on;
5441
static bool nowayout_info = WATCHDOG_NOWAYOUT;
@@ -75,22 +62,8 @@ static char *cmd_buf;
7562
static int diag288(unsigned int func, unsigned int timeout,
7663
unsigned long action, unsigned int len)
7764
{
78-
union register_pair r1 = { .even = func, .odd = timeout, };
79-
union register_pair r3 = { .even = action, .odd = len, };
80-
int err;
81-
8265
diag_stat_inc(DIAG_STAT_X288);
83-
84-
err = -EINVAL;
85-
asm volatile(
86-
" diag %[r1],%[r3],0x288\n"
87-
"0: la %[err],0\n"
88-
"1:\n"
89-
EX_TABLE(0b, 1b)
90-
: [err] "+d" (err)
91-
: [r1] "d" (r1.pair), [r3] "d" (r3.pair)
92-
: "cc", "memory");
93-
return err;
66+
return __diag288(func, timeout, action, len);
9467
}
9568

9669
static int diag288_str(unsigned int func, unsigned int timeout, char *cmd)
@@ -189,8 +162,6 @@ static struct watchdog_device wdt_dev = {
189162

190163
static int __init diag288_init(void)
191164
{
192-
int ret;
193-
194165
watchdog_set_nowayout(&wdt_dev, nowayout_info);
195166

196167
if (machine_is_vm()) {
@@ -199,24 +170,6 @@ static int __init diag288_init(void)
199170
pr_err("The watchdog cannot be initialized\n");
200171
return -ENOMEM;
201172
}
202-
203-
ret = diag288_str(WDT_FUNC_INIT, MIN_INTERVAL, "BEGIN");
204-
if (ret != 0) {
205-
pr_err("The watchdog cannot be initialized\n");
206-
kfree(cmd_buf);
207-
return -EINVAL;
208-
}
209-
} else {
210-
if (diag288(WDT_FUNC_INIT, WDT_DEFAULT_TIMEOUT,
211-
LPARWDT_RESTART, 0)) {
212-
pr_err("The watchdog cannot be initialized\n");
213-
return -EINVAL;
214-
}
215-
}
216-
217-
if (diag288(WDT_FUNC_CANCEL, 0, 0, 0)) {
218-
pr_err("The watchdog cannot be deactivated\n");
219-
return -EINVAL;
220173
}
221174

222175
return watchdog_register_device(&wdt_dev);
@@ -228,5 +181,5 @@ static void __exit diag288_exit(void)
228181
kfree(cmd_buf);
229182
}
230183

231-
module_init(diag288_init);
184+
module_cpu_feature_match(S390_CPU_FEATURE_D288, diag288_init);
232185
module_exit(diag288_exit);

0 commit comments

Comments
 (0)