#define ALT_TYPE_FACILITY_EARLY        0
 #define ALT_TYPE_FACILITY      1
+#define ALT_TYPE_SPEC          2
 
 #define ALT_DATA_SHIFT         0
 #define ALT_TYPE_SHIFT         20
                                         ALT_TYPE_FACILITY << ALT_TYPE_SHIFT    | \
                                         (facility) << ALT_DATA_SHIFT)
 
+#define ALT_SPEC(facility)             (ALT_CTX_LATE << ALT_CTX_SHIFT          | \
+                                        ALT_TYPE_SPEC << ALT_TYPE_SHIFT        | \
+                                        (facility) << ALT_DATA_SHIFT)
+
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
 
 #ifndef __ASSEMBLY__
 
 #include <linux/types.h>
+#include <asm/facility.h>
 
 extern int nospec_disable;
+extern int nobp;
+
+static inline bool nobp_enabled(void)
+{
+       if (__is_defined(__DECOMPRESSOR))
+               return false;
+       return nobp && test_facility(82);
+}
 
 void nospec_init_branches(void);
 void nospec_auto_detect(void);
 
 
 static __always_inline void bpon(void)
 {
-       asm volatile(ALTERNATIVE("nop", ".insn  rrf,0xb2e80000,0,0,13,0", ALT_FACILITY(82)));
+       asm volatile(ALTERNATIVE("nop", ".insn  rrf,0xb2e80000,0,0,13,0", ALT_SPEC(82)));
 }
 
 #endif /* __ASSEMBLY__ */
 
 // SPDX-License-Identifier: GPL-2.0
 
 #include <linux/uaccess.h>
+#include <asm/nospec-branch.h>
 #include <asm/alternative.h>
 #include <asm/facility.h>
 
                        replace = __test_facility(a->data, alt_stfle_fac_list);
                        break;
 #endif
+               case ALT_TYPE_SPEC:
+                       replace = nobp_enabled();
+                       break;
                default:
                        replace = false;
                }
 
 static noinline __init void setup_facility_list(void)
 {
        memcpy(alt_stfle_fac_list, stfle_fac_list, sizeof(alt_stfle_fac_list));
-       if (!IS_ENABLED(CONFIG_KERNEL_NOBP))
-               __clear_facility(82, alt_stfle_fac_list);
 }
 
 static __init void detect_diag9c(void)
 
        .endm
 
        .macro BPOFF
-       ALTERNATIVE "nop", ".insn rrf,0xb2e80000,0,0,12,0", ALT_FACILITY(82)
+       ALTERNATIVE "nop", ".insn rrf,0xb2e80000,0,0,12,0", ALT_SPEC(82)
        .endm
 
        .macro BPON
-       ALTERNATIVE "nop", ".insn rrf,0xb2e80000,0,0,13,0", ALT_FACILITY(82)
+       ALTERNATIVE "nop", ".insn rrf,0xb2e80000,0,0,13,0", ALT_SPEC(82)
        .endm
 
        .macro BPENTER tif_ptr,tif_mask
        ALTERNATIVE "TSTMSK \tif_ptr,\tif_mask; jz .+8; .insn rrf,0xb2e80000,0,0,13,0", \
-                   "j .+12; nop; nop", ALT_FACILITY(82)
+                   "j .+12; nop; nop", ALT_SPEC(82)
        .endm
 
        .macro BPEXIT tif_ptr,tif_mask
        TSTMSK  \tif_ptr,\tif_mask
        ALTERNATIVE "jz .+8;  .insn rrf,0xb2e80000,0,0,12,0", \
-                   "jnz .+8; .insn rrf,0xb2e80000,0,0,13,0", ALT_FACILITY(82)
+                   "jnz .+8; .insn rrf,0xb2e80000,0,0,13,0", ALT_SPEC(82)
        .endm
 
 #if IS_ENABLED(CONFIG_KVM)
 
 #include <linux/cpu.h>
 #include <asm/nospec-branch.h>
 
+int nobp = IS_ENABLED(CONFIG_KERNEL_NOBP);
+
 static int __init nobp_setup_early(char *str)
 {
        bool enabled;
                 * The user explicitly requested nobp=1, enable it and
                 * disable the expoline support.
                 */
-               __set_facility(82, alt_stfle_fac_list);
+               nobp = 1;
                if (IS_ENABLED(CONFIG_EXPOLINE))
                        nospec_disable = 1;
        } else {
-               __clear_facility(82, alt_stfle_fac_list);
+               nobp = 0;
        }
        return 0;
 }
 
 static int __init nospec_setup_early(char *str)
 {
-       __clear_facility(82, alt_stfle_fac_list);
+       nobp = 0;
        return 0;
 }
 early_param("nospec", nospec_setup_early);
                pr_info("Spectre V2 mitigation: etokens\n");
        if (nospec_uses_trampoline())
                pr_info("Spectre V2 mitigation: execute trampolines\n");
-       if (__test_facility(82, alt_stfle_fac_list))
+       if (nobp_enabled())
                pr_info("Spectre V2 mitigation: limited branch prediction\n");
        return 0;
 }
                 */
                if (__is_defined(CC_USING_EXPOLINE))
                        nospec_disable = 1;
-               __clear_facility(82, alt_stfle_fac_list);
+               nobp = 0;
        } else if (__is_defined(CC_USING_EXPOLINE)) {
                /*
                 * The kernel has been compiled with expolines.
                 * Keep expolines enabled and disable nobp.
                 */
                nospec_disable = 0;
-               __clear_facility(82, alt_stfle_fac_list);
+               nobp = 0;
        }
        /*
         * If the kernel has not been compiled with expolines the
 {
        if (str && !strncmp(str, "on", 2)) {
                nospec_disable = 0;
-               __clear_facility(82, alt_stfle_fac_list);
+               nobp = 0;
        }
        if (str && !strncmp(str, "off", 3))
                nospec_disable = 1;
 
                return sprintf(buf, "Mitigation: etokens\n");
        if (nospec_uses_trampoline())
                return sprintf(buf, "Mitigation: execute trampolines\n");
-       if (__test_facility(82, alt_stfle_fac_list))
+       if (nobp_enabled())
                return sprintf(buf, "Mitigation: limited branch prediction\n");
        return sprintf(buf, "Vulnerable\n");
 }