[S390] cleanup facility list handling
authorMartin Schwidefsky <schwidefsky@de.ibm.com>
Mon, 25 Oct 2010 14:10:51 +0000 (16:10 +0200)
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>
Mon, 25 Oct 2010 14:10:21 +0000 (16:10 +0200)
Store the facility list once at system startup with stfl/stfle and
reuse the result for all facility tests.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
12 files changed:
arch/s390/crypto/crypt_s390.h
arch/s390/include/asm/lowcore.h
arch/s390/include/asm/system.h
arch/s390/kernel/early.c
arch/s390/kernel/setup.c
arch/s390/kernel/smp.c
arch/s390/kernel/topology.c
arch/s390/kernel/vdso.c
arch/s390/kvm/kvm-s390.c
arch/s390/kvm/priv.c
arch/s390/mm/fault.c
drivers/s390/crypto/ap_bus.c

index 0ef9829..7ee9a1b 100644 (file)
@@ -297,7 +297,7 @@ static inline int crypt_s390_func_available(int func)
        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) {
index 0f97ef2..65e172f 100644 (file)
@@ -150,9 +150,10 @@ struct _lowcore {
         */
        __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 */
@@ -285,7 +286,11 @@ struct _lowcore {
         */
        __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 */
index 3c079dd..3ad16db 100644 (file)
@@ -420,30 +420,21 @@ extern void smp_ctl_clear_bit(int cr, int bit);
 
 #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)
index 0badc63..d2455d4 100644 (file)
@@ -256,13 +256,35 @@ static noinline __init void setup_lowcore_early(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);
@@ -356,18 +378,13 @@ static __init void detect_diag44(void)
 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
 }
@@ -448,6 +465,7 @@ void __init startup_init(void)
        lockdep_off();
        sort_main_extable();
        setup_lowcore_early();
+       setup_facility_list();
        detect_machine_type();
        ipl_update_parameters();
        setup_boot_command_line();
index 9071e98..e3ceb91 100644 (file)
@@ -409,6 +409,9 @@ setup_lowcore(void)
        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)
@@ -675,12 +678,9 @@ setup_memory(void)
 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
@@ -700,11 +700,10 @@ static void __init setup_hwcaps(void)
         *   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;
 
        /*
@@ -720,12 +719,8 @@ static void __init setup_hwcaps(void)
         * 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.
index 354589d..94cf510 100644 (file)
@@ -594,6 +594,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
        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)
index eb0bc47..91fb66b 100644 (file)
@@ -351,13 +351,10 @@ static void alloc_masks(struct tl_info *info, struct mask_info *mask, int offset
 
 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;
 
index 6b83870..e3150dd 100644 (file)
@@ -84,11 +84,7 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
  */
 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
index 76482b6..985d825 100644 (file)
@@ -740,7 +740,7 @@ static int __init kvm_s390_init(void)
                kvm_exit();
                return -ENOMEM;
        }
-       stfle(facilities, 1);
+       memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
        facilities[0] &= 0xff00fff3f47c0000ULL;
        return 0;
 }
index 4420550..9194a4b 100644 (file)
@@ -154,12 +154,12 @@ static int handle_chsc(struct kvm_vcpu *vcpu)
 
 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));
index b4aad0c..fe5701e 100644 (file)
@@ -56,12 +56,7 @@ static unsigned long store_indication;
 
 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;
 }
 
index 91c6028..8fd8c62 100644 (file)
@@ -154,14 +154,7 @@ static inline int ap_instructions_available(void)
  */
 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);
 }
 
 /**