aboutsummaryrefslogtreecommitdiffstats
path: root/arch/s390
diff options
context:
space:
mode:
authorMartin Schwidefsky <schwidefsky@de.ibm.com>2010-10-25 10:10:51 -0400
committerMartin Schwidefsky <sky@mschwide.boeblingen.de.ibm.com>2010-10-25 10:10:21 -0400
commit14375bc4eb8dd0fb0e765390650564c35bb31068 (patch)
tree27200620658245c582ee9497fc969a082b304cab /arch/s390
parenteca577ef5989d25dedc6b0fae3c4622ceaee8005 (diff)
[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>
Diffstat (limited to 'arch/s390')
-rw-r--r--arch/s390/crypto/crypt_s390.h2
-rw-r--r--arch/s390/include/asm/lowcore.h11
-rw-r--r--arch/s390/include/asm/system.h33
-rw-r--r--arch/s390/kernel/early.c40
-rw-r--r--arch/s390/kernel/setup.c19
-rw-r--r--arch/s390/kernel/smp.c2
-rw-r--r--arch/s390/kernel/topology.c5
-rw-r--r--arch/s390/kernel/vdso.c6
-rw-r--r--arch/s390/kvm/kvm-s390.c2
-rw-r--r--arch/s390/kvm/priv.c4
-rw-r--r--arch/s390/mm/fault.c7
11 files changed, 65 insertions, 66 deletions
diff --git a/arch/s390/crypto/crypt_s390.h b/arch/s390/crypto/crypt_s390.h
index 0ef9829f2ad6..7ee9a1b4ad9f 100644
--- a/arch/s390/crypto/crypt_s390.h
+++ b/arch/s390/crypto/crypt_s390.h
@@ -297,7 +297,7 @@ static inline int crypt_s390_func_available(int func)
297 int ret; 297 int ret;
298 298
299 /* check if CPACF facility (bit 17) is available */ 299 /* check if CPACF facility (bit 17) is available */
300 if (!(stfl() & 1ULL << (31 - 17))) 300 if (!test_facility(17))
301 return 0; 301 return 0;
302 302
303 switch (func & CRYPT_S390_OP_MASK) { 303 switch (func & CRYPT_S390_OP_MASK) {
diff --git a/arch/s390/include/asm/lowcore.h b/arch/s390/include/asm/lowcore.h
index 0f97ef2d92ac..65e172f8209d 100644
--- a/arch/s390/include/asm/lowcore.h
+++ b/arch/s390/include/asm/lowcore.h
@@ -150,9 +150,10 @@ struct _lowcore {
150 */ 150 */
151 __u32 ipib; /* 0x0e00 */ 151 __u32 ipib; /* 0x0e00 */
152 __u32 ipib_checksum; /* 0x0e04 */ 152 __u32 ipib_checksum; /* 0x0e04 */
153 __u8 pad_0x0e08[0x0f00-0x0e08]; /* 0x0e08 */
153 154
154 /* Align to the top 1k of prefix area */ 155 /* Extended facility list */
155 __u8 pad_0x0e08[0x1000-0x0e08]; /* 0x0e08 */ 156 __u64 stfle_fac_list[32]; /* 0x0f00 */
156} __packed; 157} __packed;
157 158
158#else /* CONFIG_32BIT */ 159#else /* CONFIG_32BIT */
@@ -285,7 +286,11 @@ struct _lowcore {
285 */ 286 */
286 __u64 ipib; /* 0x0e00 */ 287 __u64 ipib; /* 0x0e00 */
287 __u32 ipib_checksum; /* 0x0e08 */ 288 __u32 ipib_checksum; /* 0x0e08 */
288 __u8 pad_0x0e0c[0x11b8-0x0e0c]; /* 0x0e0c */ 289 __u8 pad_0x0e0c[0x0f00-0x0e0c]; /* 0x0e0c */
290
291 /* Extended facility list */
292 __u64 stfle_fac_list[32]; /* 0x0f00 */
293 __u8 pad_0x1000[0x11b8-0x1000]; /* 0x1000 */
289 294
290 /* 64 bit extparam used for pfault/diag 250: defined by architecture */ 295 /* 64 bit extparam used for pfault/diag 250: defined by architecture */
291 __u64 ext_params2; /* 0x11B8 */ 296 __u64 ext_params2; /* 0x11B8 */
diff --git a/arch/s390/include/asm/system.h b/arch/s390/include/asm/system.h
index 3c079dd5ee79..3ad16dbf622e 100644
--- a/arch/s390/include/asm/system.h
+++ b/arch/s390/include/asm/system.h
@@ -420,30 +420,21 @@ extern void smp_ctl_clear_bit(int cr, int bit);
420 420
421#endif /* CONFIG_SMP */ 421#endif /* CONFIG_SMP */
422 422
423static inline unsigned int stfl(void) 423#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
424{
425 asm volatile(
426 " .insn s,0xb2b10000,0(0)\n" /* stfl */
427 "0:\n"
428 EX_TABLE(0b,0b));
429 return S390_lowcore.stfl_fac_list;
430}
431 424
432static inline int __stfle(unsigned long long *list, int doublewords) 425/*
426 * The test_facility function uses the bit odering where the MSB is bit 0.
427 * That makes it easier to query facility bits with the bit number as
428 * documented in the Principles of Operation.
429 */
430static inline int test_facility(unsigned long nr)
433{ 431{
434 typedef struct { unsigned long long _[doublewords]; } addrtype; 432 unsigned char *ptr;
435 register unsigned long __nr asm("0") = doublewords - 1;
436
437 asm volatile(".insn s,0xb2b00000,%0" /* stfle */
438 : "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
439 return __nr + 1;
440}
441 433
442static inline int stfle(unsigned long long *list, int doublewords) 434 if (nr >= MAX_FACILITY_BIT)
443{ 435 return 0;
444 if (!(stfl() & (1UL << 24))) 436 ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
445 return -EOPNOTSUPP; 437 return (*ptr & (0x80 >> (nr & 7))) != 0;
446 return __stfle(list, doublewords);
447} 438}
448 439
449static inline unsigned short stap(void) 440static inline unsigned short stap(void)
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)
256 s390_base_pgm_handler_fn = early_pgm_check_handler; 256 s390_base_pgm_handler_fn = early_pgm_check_handler;
257} 257}
258 258
259static noinline __init void setup_facility_list(void)
260{
261 unsigned long nr;
262
263 S390_lowcore.stfl_fac_list = 0;
264 asm volatile(
265 " .insn s,0xb2b10000,0(0)\n" /* stfl */
266 "0:\n"
267 EX_TABLE(0b,0b) : "=m" (S390_lowcore.stfl_fac_list));
268 memcpy(&S390_lowcore.stfle_fac_list, &S390_lowcore.stfl_fac_list, 4);
269 nr = 4; /* # bytes stored by stfl */
270 if (test_facility(7)) {
271 /* More facility bits available with stfle */
272 register unsigned long reg0 asm("0") = MAX_FACILITY_BIT/64 - 1;
273 asm volatile(".insn s,0xb2b00000,%0" /* stfle */
274 : "=m" (S390_lowcore.stfle_fac_list), "+d" (reg0)
275 : : "cc");
276 nr = (reg0 + 1) * 8; /* # bytes stored by stfle */
277 }
278 memset((char *) S390_lowcore.stfle_fac_list + nr, 0,
279 MAX_FACILITY_BIT/8 - nr);
280}
281
259static noinline __init void setup_hpage(void) 282static noinline __init void setup_hpage(void)
260{ 283{
261#ifndef CONFIG_DEBUG_PAGEALLOC 284#ifndef CONFIG_DEBUG_PAGEALLOC
262 unsigned int facilities; 285 unsigned int facilities;
263 286
264 facilities = stfl(); 287 if (!test_facility(2) || !test_facility(8))
265 if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
266 return; 288 return;
267 S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE; 289 S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
268 __ctl_set_bit(0, 23); 290 __ctl_set_bit(0, 23);
@@ -356,18 +378,13 @@ static __init void detect_diag44(void)
356static __init void detect_machine_facilities(void) 378static __init void detect_machine_facilities(void)
357{ 379{
358#ifdef CONFIG_64BIT 380#ifdef CONFIG_64BIT
359 unsigned int facilities; 381 if (test_facility(3))
360 unsigned long long facility_bits;
361
362 facilities = stfl();
363 if (facilities & (1 << 28))
364 S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE; 382 S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
365 if (facilities & (1 << 23)) 383 if (test_facility(8))
366 S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF; 384 S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
367 if (facilities & (1 << 4)) 385 if (test_facility(27))
368 S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS; 386 S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
369 if ((stfle(&facility_bits, 1) > 0) && 387 if (test_facility(40))
370 (facility_bits & (1ULL << (63 - 40))))
371 S390_lowcore.machine_flags |= MACHINE_FLAG_SPP; 388 S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
372#endif 389#endif
373} 390}
@@ -448,6 +465,7 @@ void __init startup_init(void)
448 lockdep_off(); 465 lockdep_off();
449 sort_main_extable(); 466 sort_main_extable();
450 setup_lowcore_early(); 467 setup_lowcore_early();
468 setup_facility_list();
451 detect_machine_type(); 469 detect_machine_type();
452 ipl_update_parameters(); 470 ipl_update_parameters();
453 setup_boot_command_line(); 471 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)
409 lc->current_task = (unsigned long) init_thread_union.thread_info.task; 409 lc->current_task = (unsigned long) init_thread_union.thread_info.task;
410 lc->thread_info = (unsigned long) &init_thread_union; 410 lc->thread_info = (unsigned long) &init_thread_union;
411 lc->machine_flags = S390_lowcore.machine_flags; 411 lc->machine_flags = S390_lowcore.machine_flags;
412 lc->stfl_fac_list = S390_lowcore.stfl_fac_list;
413 memcpy(lc->stfle_fac_list, S390_lowcore.stfle_fac_list,
414 MAX_FACILITY_BIT/8);
412#ifndef CONFIG_64BIT 415#ifndef CONFIG_64BIT
413 if (MACHINE_HAS_IEEE) { 416 if (MACHINE_HAS_IEEE) {
414 lc->extended_save_area_addr = (__u32) 417 lc->extended_save_area_addr = (__u32)
@@ -675,12 +678,9 @@ setup_memory(void)
675static void __init setup_hwcaps(void) 678static void __init setup_hwcaps(void)
676{ 679{
677 static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 }; 680 static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
678 unsigned long long facility_list_extended;
679 unsigned int facility_list;
680 struct cpuid cpu_id; 681 struct cpuid cpu_id;
681 int i; 682 int i;
682 683
683 facility_list = stfl();
684 /* 684 /*
685 * The store facility list bits numbers as found in the principles 685 * The store facility list bits numbers as found in the principles
686 * of operation are numbered with bit 1UL<<31 as number 0 to 686 * of operation are numbered with bit 1UL<<31 as number 0 to
@@ -700,11 +700,10 @@ static void __init setup_hwcaps(void)
700 * HWCAP_S390_ETF3EH bit 8 (22 && 30). 700 * HWCAP_S390_ETF3EH bit 8 (22 && 30).
701 */ 701 */
702 for (i = 0; i < 6; i++) 702 for (i = 0; i < 6; i++)
703 if (facility_list & (1UL << (31 - stfl_bits[i]))) 703 if (test_facility(stfl_bits[i]))
704 elf_hwcap |= 1UL << i; 704 elf_hwcap |= 1UL << i;
705 705
706 if ((facility_list & (1UL << (31 - 22))) 706 if (test_facility(22) && test_facility(30))
707 && (facility_list & (1UL << (31 - 30))))
708 elf_hwcap |= HWCAP_S390_ETF3EH; 707 elf_hwcap |= HWCAP_S390_ETF3EH;
709 708
710 /* 709 /*
@@ -720,12 +719,8 @@ static void __init setup_hwcaps(void)
720 * translated to: 719 * translated to:
721 * HWCAP_S390_DFP bit 6 (42 && 44). 720 * HWCAP_S390_DFP bit 6 (42 && 44).
722 */ 721 */
723 if ((elf_hwcap & (1UL << 2)) && 722 if ((elf_hwcap & (1UL << 2)) && test_facility(42) && test_facility(44))
724 __stfle(&facility_list_extended, 1) > 0) { 723 elf_hwcap |= HWCAP_S390_DFP;
725 if ((facility_list_extended & (1ULL << (63 - 42)))
726 && (facility_list_extended & (1ULL << (63 - 44))))
727 elf_hwcap |= HWCAP_S390_DFP;
728 }
729 724
730 /* 725 /*
731 * Huge page support HWCAP_S390_HPAGE is bit 7. 726 * 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)
594 cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce; 594 cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
595 cpu_lowcore->machine_flags = S390_lowcore.machine_flags; 595 cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
596 cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func; 596 cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
597 memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
598 MAX_FACILITY_BIT/8);
597 eieio(); 599 eieio();
598 600
599 while (sigp(cpu, sigp_restart) == sigp_busy) 601 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
351 351
352void __init s390_init_cpu_topology(void) 352void __init s390_init_cpu_topology(void)
353{ 353{
354 unsigned long long facility_bits;
355 struct tl_info *info; 354 struct tl_info *info;
356 int i; 355 int i;
357 356
358 if (stfle(&facility_bits, 1) <= 0) 357 if (!test_facility(2) || !test_facility(11))
359 return;
360 if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
361 return; 358 return;
362 machine_has_topology = 1; 359 machine_has_topology = 1;
363 360
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;
84 */ 84 */
85static void vdso_init_data(struct vdso_data *vd) 85static void vdso_init_data(struct vdso_data *vd)
86{ 86{
87 unsigned int facility_list; 87 vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
88
89 facility_list = stfl();
90 vd->ectg_available =
91 user_mode != HOME_SPACE_MODE && (facility_list & 1);
92} 88}
93 89
94#ifdef CONFIG_64BIT 90#ifdef CONFIG_64BIT
diff --git a/arch/s390/kvm/kvm-s390.c b/arch/s390/kvm/kvm-s390.c
index 76482b65ba3e..985d825494f1 100644
--- a/arch/s390/kvm/kvm-s390.c
+++ b/arch/s390/kvm/kvm-s390.c
@@ -740,7 +740,7 @@ static int __init kvm_s390_init(void)
740 kvm_exit(); 740 kvm_exit();
741 return -ENOMEM; 741 return -ENOMEM;
742 } 742 }
743 stfle(facilities, 1); 743 memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
744 facilities[0] &= 0xff00fff3f47c0000ULL; 744 facilities[0] &= 0xff00fff3f47c0000ULL;
745 return 0; 745 return 0;
746} 746}
diff --git a/arch/s390/kvm/priv.c b/arch/s390/kvm/priv.c
index 44205507717c..9194a4b52b22 100644
--- a/arch/s390/kvm/priv.c
+++ b/arch/s390/kvm/priv.c
@@ -154,12 +154,12 @@ static int handle_chsc(struct kvm_vcpu *vcpu)
154 154
155static int handle_stfl(struct kvm_vcpu *vcpu) 155static int handle_stfl(struct kvm_vcpu *vcpu)
156{ 156{
157 unsigned int facility_list = stfl(); 157 unsigned int facility_list;
158 int rc; 158 int rc;
159 159
160 vcpu->stat.instruction_stfl++; 160 vcpu->stat.instruction_stfl++;
161 /* only pass the facility bits, which we can handle */ 161 /* only pass the facility bits, which we can handle */
162 facility_list &= 0xff00fff3; 162 facility_list = S390_lowcore.stfl_fac_list & 0xff00fff3;
163 163
164 rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list), 164 rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
165 &facility_list, sizeof(facility_list)); 165 &facility_list, sizeof(facility_list));
diff --git a/arch/s390/mm/fault.c b/arch/s390/mm/fault.c
index b4aad0c1f562..fe5701e9efbf 100644
--- a/arch/s390/mm/fault.c
+++ b/arch/s390/mm/fault.c
@@ -56,12 +56,7 @@ static unsigned long store_indication;
56 56
57void fault_init(void) 57void fault_init(void)
58{ 58{
59 unsigned long long facility_list[2]; 59 if (test_facility(2) && test_facility(75))
60
61 if (stfle(facility_list, 2) < 2)
62 return;
63 if ((facility_list[0] & (1ULL << 61)) &&
64 (facility_list[1] & (1ULL << 52)))
65 store_indication = 0xc00; 60 store_indication = 0xc00;
66} 61}
67 62