From 14375bc4eb8dd0fb0e765390650564c35bb31068 Mon Sep 17 00:00:00 2001
From: Martin Schwidefsky <schwidefsky@de.ibm.com>
Date: Mon, 25 Oct 2010 16:10:51 +0200
Subject: [S390] cleanup facility list handling

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>
---
 arch/s390/kernel/early.c    | 40 +++++++++++++++++++++++++++++-----------
 arch/s390/kernel/setup.c    | 19 +++++++------------
 arch/s390/kernel/smp.c      |  2 ++
 arch/s390/kernel/topology.c |  5 +----
 arch/s390/kernel/vdso.c     |  6 +-----
 5 files changed, 40 insertions(+), 32 deletions(-)

(limited to 'arch/s390/kernel')

diff --git a/arch/s390/kernel/early.c b/arch/s390/kernel/early.c
index 0badc6344eb4..d2455d44d99a 100644
--- a/arch/s390/kernel/early.c
+++ b/arch/s390/kernel/early.c
@@ -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();
diff --git a/arch/s390/kernel/setup.c b/arch/s390/kernel/setup.c
index 9071e984dcf1..e3ceb911dc75 100644
--- a/arch/s390/kernel/setup.c
+++ b/arch/s390/kernel/setup.c
@@ -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.
diff --git a/arch/s390/kernel/smp.c b/arch/s390/kernel/smp.c
index 354589d096b1..94cf510b8fe1 100644
--- a/arch/s390/kernel/smp.c
+++ b/arch/s390/kernel/smp.c
@@ -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)
diff --git a/arch/s390/kernel/topology.c b/arch/s390/kernel/topology.c
index eb0bc4752ae8..91fb66baa50b 100644
--- a/arch/s390/kernel/topology.c
+++ b/arch/s390/kernel/topology.c
@@ -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;
 
diff --git a/arch/s390/kernel/vdso.c b/arch/s390/kernel/vdso.c
index 6b83870507d5..e3150dd2fe74 100644
--- a/arch/s390/kernel/vdso.c
+++ b/arch/s390/kernel/vdso.c
@@ -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
-- 
cgit v1.2.3