Commit 1c745df5 authored by Heiko Carstens's avatar Heiko Carstens
Browse files

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: default avatarMarc Hartmayer <mhartmay@linux.ibm.com>
Tested-by: default avatarMete Durlu <meted@linux.ibm.com>
Acked-by: default avatarGuenter Roeck <linux@roeck-us.net>
Link: https://lore.kernel.org/r/20250410095036.1525057-1-hca@linux.ibm.com


Signed-off-by: default avatarHeiko Carstens <hca@linux.ibm.com>
parent 1468d6b1
Loading
Loading
Loading
Loading
+17 −0
Original line number Diff line number Diff line
@@ -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();
+1 −0
Original line number Diff line number Diff line
@@ -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 −0
Original line number Diff line number Diff line
/* 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 */
+1 −0
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@
#define MFEATURE_VM		7
#define MFEATURE_KVM		8
#define MFEATURE_LPAR		9
#define MFEATURE_DIAG288	10

#ifndef __ASSEMBLY__

+5 −0
Original line number Diff line number Diff line
@@ -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;
Loading