int ret;
 
        /* check if CPACF facility (bit 17) is available */
-       if (!(stfl() & 1ULL << (31 - 17)))
+       if (!test_facility(17))
                return 0;
 
        switch (func & CRYPT_S390_OP_MASK) {
 
         */
        __u32   ipib;                           /* 0x0e00 */
        __u32   ipib_checksum;                  /* 0x0e04 */
+       __u8    pad_0x0e08[0x0f00-0x0e08];      /* 0x0e08 */
 
-       /* Align to the top 1k of prefix area */
-       __u8    pad_0x0e08[0x1000-0x0e08];      /* 0x0e08 */
+       /* Extended facility list */
+       __u64   stfle_fac_list[32];             /* 0x0f00 */
 } __packed;
 
 #else /* CONFIG_32BIT */
         */
        __u64   ipib;                           /* 0x0e00 */
        __u32   ipib_checksum;                  /* 0x0e08 */
-       __u8    pad_0x0e0c[0x11b8-0x0e0c];      /* 0x0e0c */
+       __u8    pad_0x0e0c[0x0f00-0x0e0c];      /* 0x0e0c */
+
+       /* Extended facility list */
+       __u64   stfle_fac_list[32];             /* 0x0f00 */
+       __u8    pad_0x1000[0x11b8-0x1000];      /* 0x1000 */
 
        /* 64 bit extparam used for pfault/diag 250: defined by architecture */
        __u64   ext_params2;                    /* 0x11B8 */
 
 
 #endif /* CONFIG_SMP */
 
-static inline unsigned int stfl(void)
-{
-       asm volatile(
-               "       .insn   s,0xb2b10000,0(0)\n" /* stfl */
-               "0:\n"
-               EX_TABLE(0b,0b));
-       return S390_lowcore.stfl_fac_list;
-}
+#define MAX_FACILITY_BIT (256*8)       /* stfle_fac_list has 256 bytes */
 
-static inline int __stfle(unsigned long long *list, int doublewords)
+/*
+ * The test_facility function uses the bit odering where the MSB is bit 0.
+ * That makes it easier to query facility bits with the bit number as
+ * documented in the Principles of Operation.
+ */
+static inline int test_facility(unsigned long nr)
 {
-       typedef struct { unsigned long long _[doublewords]; } addrtype;
-       register unsigned long __nr asm("0") = doublewords - 1;
-
-       asm volatile(".insn s,0xb2b00000,%0" /* stfle */
-                    : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
-       return __nr + 1;
-}
+       unsigned char *ptr;
 
-static inline int stfle(unsigned long long *list, int doublewords)
-{
-       if (!(stfl() & (1UL << 24)))
-               return -EOPNOTSUPP;
-       return __stfle(list, doublewords);
+       if (nr >= MAX_FACILITY_BIT)
+               return 0;
+       ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
+       return (*ptr & (0x80 >> (nr & 7))) != 0;
 }
 
 static inline unsigned short stap(void)
 
        s390_base_pgm_handler_fn = early_pgm_check_handler;
 }
 
+static noinline __init void setup_facility_list(void)
+{
+       unsigned long nr;
+
+       S390_lowcore.stfl_fac_list = 0;
+       asm volatile(
+               "       .insn   s,0xb2b10000,0(0)\n" /* stfl */
+               "0:\n"
+               EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
+       memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
+       nr = 4;                         /* # bytes stored by stfl */
+       if (test_facility(7)) {
+               /* More facility bits available with stfle */
+               register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
+               asm volatile(".insn s,0xb2b00000,%0" /* stfle */
+                            : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
+                            : : "cc");
+               nr = (reg0 + 1) * 8;    /* # bytes stored by stfle */
+       }
+       memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
+              MAX_FACILITY_BIT/8 - nr);
+}
+
 static noinline __init void setup_hpage(void)
 {
 #ifndef CONFIG_DEBUG_PAGEALLOC
        unsigned int facilities;
 
-       facilities = stfl();
-       if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
+       if (!test_facility(2) || !test_facility(8))
                return;
        S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
        __ctl_set_bit(0, 23);
 static __init void detect_machine_facilities(void)
 {
 #ifdef CONFIG_64BIT
-       unsigned int facilities;
-       unsigned long long facility_bits;
-
-       facilities = stfl();
-       if (facilities & (1 << 28))
+       if (test_facility(3))
                S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
-       if (facilities & (1 << 23))
+       if (test_facility(8))
                S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
-       if (facilities & (1 << 4))
+       if (test_facility(27))
                S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
-       if ((stfle(&facility_bits, 1) > 0) &&
-           (facility_bits & (1ULL << (63 - 40))))
+       if (test_facility(40))
                S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
 #endif
 }
        lockdep_off();
        sort_main_extable();
        setup_lowcore_early();
+       setup_facility_list();
        detect_machine_type();
        ipl_update_parameters();
        setup_boot_command_line();
 
        lc->current_task = (unsigned long) init_thread_union.thread_info.task;
        lc->thread_info = (unsigned long) &init_thread_union;
        lc->machine_flags = S390_lowcore.machine_flags;
+       lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
+       memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
+              MAX_FACILITY_BIT/8);
 #ifndef CONFIG_64BIT
        if (MACHINE_HAS_IEEE) {
                lc->extended_save_area_addr = (__u32)
 static void __init setup_hwcaps(void)
 {
        static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
-       unsigned long long facility_list_extended;
-       unsigned int facility_list;
        struct cpuid cpu_id;
        int i;
 
-       facility_list = stfl();
        /*
         * The store facility list bits numbers as found in the principles
         * of operation are numbered with bit 1UL<<31 as number 0 to
         *   HWCAP_S390_ETF3EH bit 8 (22 && 30).
         */
        for (i = 0; i < 6; i++)
-               if (facility_list & (1UL << (31 - stfl_bits[i])))
+               if (test_facility(stfl_bits[i]))
                        elf_hwcap |= 1UL << i;
 
-       if ((facility_list & (1UL << (31 - 22)))
-           && (facility_list & (1UL << (31 - 30))))
+       if (test_facility(22) && test_facility(30))
                elf_hwcap |= HWCAP_S390_ETF3EH;
 
        /*
         * translated to:
         *   HWCAP_S390_DFP bit 6 (42 && 44).
         */
-       if ((elf_hwcap & (1UL << 2)) &&
-           __stfle(&facility_list_extended, 1) > 0) {
-               if ((facility_list_extended & (1ULL << (63 - 42)))
-                   && (facility_list_extended & (1ULL << (63 - 44))))
-                       elf_hwcap |= HWCAP_S390_DFP;
-       }
+       if ((elf_hwcap & (1UL << 2)) && test_facility(42) && test_facility(44))
+               elf_hwcap |= HWCAP_S390_DFP;
 
        /*
         * Huge page support HWCAP_S390_HPAGE is bit 7.
 
        cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
        cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
        cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
+       memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
+              MAX_FACILITY_BIT/8);
        eieio();
 
        while (sigp(cpu, sigp_restart) == sigp_busy)
 
 
 void __init s390_init_cpu_topology(void)
 {
-       unsigned long long facility_bits;
        struct tl_info *info;
        int i;
 
-       if (stfle(&facility_bits, 1) <= 0)
-               return;
-       if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
+       if (!test_facility(2) || !test_facility(11))
                return;
        machine_has_topology = 1;
 
 
  */
 static void vdso_init_data(struct vdso_data *vd)
 {
-       unsigned int facility_list;
-
-       facility_list = stfl();
-       vd->ectg_available =
-               user_mode != HOME_SPACE_MODE && (facility_list & 1);
+       vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
 }
 
 #ifdef CONFIG_64BIT
 
                kvm_exit();
                return -ENOMEM;
        }
-       stfle(facilities, 1);
+       memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
        facilities[0] &= 0xff00fff3f47c0000ULL;
        return 0;
 }
 
 
 static int handle_stfl(struct kvm_vcpu *vcpu)
 {
-       unsigned int facility_list = stfl();
+       unsigned int facility_list;
        int rc;
 
        vcpu->stat.instruction_stfl++;
        /* only pass the facility bits, which we can handle */
-       facility_list &= 0xff00fff3;
+       facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
 
        rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
                           &facility_list, sizeof(facility_list));
 
 
 void fault_init(void)
 {
-       unsigned long long facility_list[2];
-
-       if (stfle(facility_list, 2) < 2)
-               return;
-       if ((facility_list[0] & (1ULL << 61)) &&
-           (facility_list[1] & (1ULL << 52)))
+       if (test_facility(2) && test_facility(75))
                store_indication = 0xc00;
 }
 
 
  */
 static int ap_interrupts_available(void)
 {
-       unsigned long long facility_bits[2];
-
-       if (stfle(facility_bits, 2) <= 1)
-               return 0;
-       if (!(facility_bits[0] & (1ULL << 61)) ||
-           !(facility_bits[1] & (1ULL << 62)))
-               return 0;
-       return 1;
+       return test_facility(1) && test_facility(2);
 }
 
 /**