]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
s390: Static branches for machine features infrastructure
authorHeiko Carstens <hca@linux.ibm.com>
Fri, 7 Feb 2025 14:48:56 +0000 (15:48 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Tue, 4 Mar 2025 16:18:05 +0000 (17:18 +0100)
Provide infrastructure which allows to generate machine_has_<feature>()
functions, which are replacing the existing MACHINE_HAS_<feature> macros.
Such function usages generate a static branch depending on <feature>. The
static branch is patched using an alternative.

Each <feature> correlates with a bit set in the machine_features bit
field. If the corresponding bit is set, the branch will be patched. In
order to have any effect on branch patching feature bits must be set with
set_machine_features() in the decompressor before alternatives patching of
the kernel image.

It is possible to use clear_machine_feature() and test_machine_feature()
for machine features which cannot be completely detected within the
decompressor, e.g. if common code command line parameters allow to enable
or disable certain features. In such cases test_machine_feature() instead
of machine_has_feature() must be used within the kernel. This results in a
runtime check and not a static branch.

Reviewed-by: Vasily Gorbik <gor@linux.ibm.com>
Signed-off-by: Heiko Carstens <hca@linux.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/include/asm/alternative.h
arch/s390/include/asm/machine.h [new file with mode: 0644]
arch/s390/kernel/alternative.c

index 73e781b56bfe893688ef71b92f785361e43e2d03..67abef07ac93108c3c79a7985e1d22057a955925 100644 (file)
@@ -32,8 +32,9 @@
 #define ALT_CTX_ALL            (ALT_CTX_EARLY | ALT_CTX_LATE)
 
 #define ALT_TYPE_FACILITY      0
-#define ALT_TYPE_SPEC          1
-#define ALT_TYPE_LOWCORE       2
+#define ALT_TYPE_FEATURE       1
+#define ALT_TYPE_SPEC          2
+#define ALT_TYPE_LOWCORE       3
 
 #define ALT_DATA_SHIFT         0
 #define ALT_TYPE_SHIFT         20
                                         ALT_TYPE_FACILITY << ALT_TYPE_SHIFT    | \
                                         (facility) << ALT_DATA_SHIFT)
 
+#define ALT_FEATURE(feature)           (ALT_CTX_EARLY << ALT_CTX_SHIFT         | \
+                                        ALT_TYPE_FEATURE << ALT_TYPE_SHIFT     | \
+                                        (feature) << ALT_DATA_SHIFT)
+
 #define ALT_SPEC(facility)             (ALT_CTX_LATE << ALT_CTX_SHIFT          | \
                                         ALT_TYPE_SPEC << ALT_TYPE_SHIFT        | \
                                         (facility) << ALT_DATA_SHIFT)
diff --git a/arch/s390/include/asm/machine.h b/arch/s390/include/asm/machine.h
new file mode 100644 (file)
index 0000000..bbe6c24
--- /dev/null
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright IBM Corp. 2024
+ */
+
+#ifndef __ASM_S390_MACHINE_H
+#define __ASM_S390_MACHINE_H
+
+#ifndef __ASSEMBLY__
+
+#include <linux/bitops.h>
+#include <asm/alternative.h>
+
+extern unsigned long machine_features[1];
+
+#define MAX_MFEATURE_BIT (sizeof(machine_features) * BITS_PER_BYTE)
+
+static inline void __set_machine_feature(unsigned int nr, unsigned long *mfeatures)
+{
+       if (nr >= MAX_MFEATURE_BIT)
+               return;
+       __set_bit(nr, mfeatures);
+}
+
+static inline void set_machine_feature(unsigned int nr)
+{
+       __set_machine_feature(nr, machine_features);
+}
+
+static inline void __clear_machine_feature(unsigned int nr, unsigned long *mfeatures)
+{
+       if (nr >= MAX_MFEATURE_BIT)
+               return;
+       __clear_bit(nr, mfeatures);
+}
+
+static inline void clear_machine_feature(unsigned int nr)
+{
+       __clear_machine_feature(nr, machine_features);
+}
+
+static bool __test_machine_feature(unsigned int nr, unsigned long *mfeatures)
+{
+       if (nr >= MAX_MFEATURE_BIT)
+               return false;
+       return test_bit(nr, mfeatures);
+}
+
+static bool test_machine_feature(unsigned int nr)
+{
+       return __test_machine_feature(nr, machine_features);
+}
+
+static __always_inline bool __test_machine_feature_constant(unsigned int nr)
+{
+       asm goto(
+               ALTERNATIVE("brcl 15,%l[l_no]", "brcl 0,0", ALT_FEATURE(%[nr]))
+               :
+               : [nr] "i" (nr)
+               :
+               : l_no);
+       return true;
+l_no:
+       return false;
+}
+
+#define DEFINE_MACHINE_HAS_FEATURE(name, feature)                              \
+static __always_inline bool machine_has_##name(void)                           \
+{                                                                              \
+       if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(feature))     \
+               return __test_machine_feature_constant(feature);                \
+       return test_machine_feature(feature);                                   \
+}
+
+#endif /* __ASSEMBLY__ */
+#endif /* __ASM_S390_MACHINE_H */
index 8d5d0de35de05d8ef02e4a144144ff8ae2fea859..d3839fc0543dc727d485cb6d514ed5dbb7bde645 100644 (file)
@@ -5,6 +5,10 @@
 #include <asm/abs_lowcore.h>
 #include <asm/alternative.h>
 #include <asm/facility.h>
+#include <asm/sections.h>
+#include <asm/machine.h>
+
+unsigned long __bootdata_preserved(machine_features[1]);
 
 void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsigned int ctx)
 {
@@ -23,6 +27,9 @@ void __apply_alternatives(struct alt_instr *start, struct alt_instr *end, unsign
                case ALT_TYPE_FACILITY:
                        replace = test_facility(a->data);
                        break;
+               case ALT_TYPE_FEATURE:
+                       replace = test_machine_feature(a->data);
+                       break;
                case ALT_TYPE_SPEC:
                        replace = nobp_enabled();
                        break;