[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>
This commit is contained in:
parent
eca577ef59
commit
14375bc4eb
|
@ -297,7 +297,7 @@ static inline int crypt_s390_func_available(int func)
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
/* check if CPACF facility (bit 17) is available */
|
/* check if CPACF facility (bit 17) is available */
|
||||||
if (!(stfl() & 1ULL << (31 - 17)))
|
if (!test_facility(17))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
switch (func & CRYPT_S390_OP_MASK) {
|
switch (func & CRYPT_S390_OP_MASK) {
|
||||||
|
|
|
@ -150,9 +150,10 @@ struct _lowcore {
|
||||||
*/
|
*/
|
||||||
__u32 ipib; /* 0x0e00 */
|
__u32 ipib; /* 0x0e00 */
|
||||||
__u32 ipib_checksum; /* 0x0e04 */
|
__u32 ipib_checksum; /* 0x0e04 */
|
||||||
|
__u8 pad_0x0e08[0x0f00-0x0e08]; /* 0x0e08 */
|
||||||
|
|
||||||
/* Align to the top 1k of prefix area */
|
/* Extended facility list */
|
||||||
__u8 pad_0x0e08[0x1000-0x0e08]; /* 0x0e08 */
|
__u64 stfle_fac_list[32]; /* 0x0f00 */
|
||||||
} __packed;
|
} __packed;
|
||||||
|
|
||||||
#else /* CONFIG_32BIT */
|
#else /* CONFIG_32BIT */
|
||||||
|
@ -285,7 +286,11 @@ struct _lowcore {
|
||||||
*/
|
*/
|
||||||
__u64 ipib; /* 0x0e00 */
|
__u64 ipib; /* 0x0e00 */
|
||||||
__u32 ipib_checksum; /* 0x0e08 */
|
__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 */
|
/* 64 bit extparam used for pfault/diag 250: defined by architecture */
|
||||||
__u64 ext_params2; /* 0x11B8 */
|
__u64 ext_params2; /* 0x11B8 */
|
||||||
|
|
|
@ -420,30 +420,21 @@ extern void smp_ctl_clear_bit(int cr, int bit);
|
||||||
|
|
||||||
#endif /* CONFIG_SMP */
|
#endif /* CONFIG_SMP */
|
||||||
|
|
||||||
static inline unsigned int stfl(void)
|
#define MAX_FACILITY_BIT (256*8) /* stfle_fac_list has 256 bytes */
|
||||||
{
|
|
||||||
asm volatile(
|
|
||||||
" .insn s,0xb2b10000,0(0)\n" /* stfl */
|
|
||||||
"0:\n"
|
|
||||||
EX_TABLE(0b,0b));
|
|
||||||
return S390_lowcore.stfl_fac_list;
|
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
unsigned char *ptr;
|
||||||
register unsigned long __nr asm("0") = doublewords - 1;
|
|
||||||
|
|
||||||
asm volatile(".insn s,0xb2b00000,%0" /* stfle */
|
if (nr >= MAX_FACILITY_BIT)
|
||||||
: "=m" (*(addrtype *) list), "+d" (__nr) : : "cc");
|
return 0;
|
||||||
return __nr + 1;
|
ptr = (unsigned char *) &S390_lowcore.stfle_fac_list + (nr >> 3);
|
||||||
}
|
return (*ptr & (0x80 >> (nr & 7))) != 0;
|
||||||
|
|
||||||
static inline int stfle(unsigned long long *list, int doublewords)
|
|
||||||
{
|
|
||||||
if (!(stfl() & (1UL << 24)))
|
|
||||||
return -EOPNOTSUPP;
|
|
||||||
return __stfle(list, doublewords);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned short stap(void)
|
static inline unsigned short stap(void)
|
||||||
|
|
|
@ -256,13 +256,35 @@ static noinline __init void setup_lowcore_early(void)
|
||||||
s390_base_pgm_handler_fn = early_pgm_check_handler;
|
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)
|
static noinline __init void setup_hpage(void)
|
||||||
{
|
{
|
||||||
#ifndef CONFIG_DEBUG_PAGEALLOC
|
#ifndef CONFIG_DEBUG_PAGEALLOC
|
||||||
unsigned int facilities;
|
unsigned int facilities;
|
||||||
|
|
||||||
facilities = stfl();
|
if (!test_facility(2) || !test_facility(8))
|
||||||
if (!(facilities & (1UL << 23)) || !(facilities & (1UL << 29)))
|
|
||||||
return;
|
return;
|
||||||
S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
|
S390_lowcore.machine_flags |= MACHINE_FLAG_HPAGE;
|
||||||
__ctl_set_bit(0, 23);
|
__ctl_set_bit(0, 23);
|
||||||
|
@ -356,18 +378,13 @@ static __init void detect_diag44(void)
|
||||||
static __init void detect_machine_facilities(void)
|
static __init void detect_machine_facilities(void)
|
||||||
{
|
{
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
unsigned int facilities;
|
if (test_facility(3))
|
||||||
unsigned long long facility_bits;
|
|
||||||
|
|
||||||
facilities = stfl();
|
|
||||||
if (facilities & (1 << 28))
|
|
||||||
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
|
S390_lowcore.machine_flags |= MACHINE_FLAG_IDTE;
|
||||||
if (facilities & (1 << 23))
|
if (test_facility(8))
|
||||||
S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
|
S390_lowcore.machine_flags |= MACHINE_FLAG_PFMF;
|
||||||
if (facilities & (1 << 4))
|
if (test_facility(27))
|
||||||
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
|
S390_lowcore.machine_flags |= MACHINE_FLAG_MVCOS;
|
||||||
if ((stfle(&facility_bits, 1) > 0) &&
|
if (test_facility(40))
|
||||||
(facility_bits & (1ULL << (63 - 40))))
|
|
||||||
S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
|
S390_lowcore.machine_flags |= MACHINE_FLAG_SPP;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -448,6 +465,7 @@ void __init startup_init(void)
|
||||||
lockdep_off();
|
lockdep_off();
|
||||||
sort_main_extable();
|
sort_main_extable();
|
||||||
setup_lowcore_early();
|
setup_lowcore_early();
|
||||||
|
setup_facility_list();
|
||||||
detect_machine_type();
|
detect_machine_type();
|
||||||
ipl_update_parameters();
|
ipl_update_parameters();
|
||||||
setup_boot_command_line();
|
setup_boot_command_line();
|
||||||
|
|
|
@ -409,6 +409,9 @@ setup_lowcore(void)
|
||||||
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
|
lc->current_task = (unsigned long) init_thread_union.thread_info.task;
|
||||||
lc->thread_info = (unsigned long) &init_thread_union;
|
lc->thread_info = (unsigned long) &init_thread_union;
|
||||||
lc->machine_flags = S390_lowcore.machine_flags;
|
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
|
#ifndef CONFIG_64BIT
|
||||||
if (MACHINE_HAS_IEEE) {
|
if (MACHINE_HAS_IEEE) {
|
||||||
lc->extended_save_area_addr = (__u32)
|
lc->extended_save_area_addr = (__u32)
|
||||||
|
@ -675,12 +678,9 @@ setup_memory(void)
|
||||||
static void __init setup_hwcaps(void)
|
static void __init setup_hwcaps(void)
|
||||||
{
|
{
|
||||||
static const int stfl_bits[6] = { 0, 2, 7, 17, 19, 21 };
|
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;
|
struct cpuid cpu_id;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
facility_list = stfl();
|
|
||||||
/*
|
/*
|
||||||
* The store facility list bits numbers as found in the principles
|
* The store facility list bits numbers as found in the principles
|
||||||
* of operation are numbered with bit 1UL<<31 as number 0 to
|
* 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).
|
* HWCAP_S390_ETF3EH bit 8 (22 && 30).
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < 6; i++)
|
for (i = 0; i < 6; i++)
|
||||||
if (facility_list & (1UL << (31 - stfl_bits[i])))
|
if (test_facility(stfl_bits[i]))
|
||||||
elf_hwcap |= 1UL << i;
|
elf_hwcap |= 1UL << i;
|
||||||
|
|
||||||
if ((facility_list & (1UL << (31 - 22)))
|
if (test_facility(22) && test_facility(30))
|
||||||
&& (facility_list & (1UL << (31 - 30))))
|
|
||||||
elf_hwcap |= HWCAP_S390_ETF3EH;
|
elf_hwcap |= HWCAP_S390_ETF3EH;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -720,12 +719,8 @@ static void __init setup_hwcaps(void)
|
||||||
* translated to:
|
* translated to:
|
||||||
* HWCAP_S390_DFP bit 6 (42 && 44).
|
* HWCAP_S390_DFP bit 6 (42 && 44).
|
||||||
*/
|
*/
|
||||||
if ((elf_hwcap & (1UL << 2)) &&
|
if ((elf_hwcap & (1UL << 2)) && test_facility(42) && test_facility(44))
|
||||||
__stfle(&facility_list_extended, 1) > 0) {
|
|
||||||
if ((facility_list_extended & (1ULL << (63 - 42)))
|
|
||||||
&& (facility_list_extended & (1ULL << (63 - 44))))
|
|
||||||
elf_hwcap |= HWCAP_S390_DFP;
|
elf_hwcap |= HWCAP_S390_DFP;
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Huge page support HWCAP_S390_HPAGE is bit 7.
|
* Huge page support HWCAP_S390_HPAGE is bit 7.
|
||||||
|
|
|
@ -594,6 +594,8 @@ int __cpuinit __cpu_up(unsigned int cpu)
|
||||||
cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
|
cpu_lowcore->kernel_asce = S390_lowcore.kernel_asce;
|
||||||
cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
|
cpu_lowcore->machine_flags = S390_lowcore.machine_flags;
|
||||||
cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
|
cpu_lowcore->ftrace_func = S390_lowcore.ftrace_func;
|
||||||
|
memcpy(cpu_lowcore->stfle_fac_list, S390_lowcore.stfle_fac_list,
|
||||||
|
MAX_FACILITY_BIT/8);
|
||||||
eieio();
|
eieio();
|
||||||
|
|
||||||
while (sigp(cpu, sigp_restart) == sigp_busy)
|
while (sigp(cpu, sigp_restart) == sigp_busy)
|
||||||
|
|
|
@ -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)
|
void __init s390_init_cpu_topology(void)
|
||||||
{
|
{
|
||||||
unsigned long long facility_bits;
|
|
||||||
struct tl_info *info;
|
struct tl_info *info;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
if (stfle(&facility_bits, 1) <= 0)
|
if (!test_facility(2) || !test_facility(11))
|
||||||
return;
|
|
||||||
if (!(facility_bits & (1ULL << 52)) || !(facility_bits & (1ULL << 61)))
|
|
||||||
return;
|
return;
|
||||||
machine_has_topology = 1;
|
machine_has_topology = 1;
|
||||||
|
|
||||||
|
|
|
@ -84,11 +84,7 @@ struct vdso_data *vdso_data = &vdso_data_store.data;
|
||||||
*/
|
*/
|
||||||
static void vdso_init_data(struct vdso_data *vd)
|
static void vdso_init_data(struct vdso_data *vd)
|
||||||
{
|
{
|
||||||
unsigned int facility_list;
|
vd->ectg_available = user_mode != HOME_SPACE_MODE && test_facility(31);
|
||||||
|
|
||||||
facility_list = stfl();
|
|
||||||
vd->ectg_available =
|
|
||||||
user_mode != HOME_SPACE_MODE && (facility_list & 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_64BIT
|
#ifdef CONFIG_64BIT
|
||||||
|
|
|
@ -740,7 +740,7 @@ static int __init kvm_s390_init(void)
|
||||||
kvm_exit();
|
kvm_exit();
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
stfle(facilities, 1);
|
memcpy(facilities, S390_lowcore.stfle_fac_list, 16);
|
||||||
facilities[0] &= 0xff00fff3f47c0000ULL;
|
facilities[0] &= 0xff00fff3f47c0000ULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -154,12 +154,12 @@ static int handle_chsc(struct kvm_vcpu *vcpu)
|
||||||
|
|
||||||
static int handle_stfl(struct kvm_vcpu *vcpu)
|
static int handle_stfl(struct kvm_vcpu *vcpu)
|
||||||
{
|
{
|
||||||
unsigned int facility_list = stfl();
|
unsigned int facility_list;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
vcpu->stat.instruction_stfl++;
|
vcpu->stat.instruction_stfl++;
|
||||||
/* only pass the facility bits, which we can handle */
|
/* 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),
|
rc = copy_to_guest(vcpu, offsetof(struct _lowcore, stfl_fac_list),
|
||||||
&facility_list, sizeof(facility_list));
|
&facility_list, sizeof(facility_list));
|
||||||
|
|
|
@ -56,12 +56,7 @@ static unsigned long store_indication;
|
||||||
|
|
||||||
void fault_init(void)
|
void fault_init(void)
|
||||||
{
|
{
|
||||||
unsigned long long facility_list[2];
|
if (test_facility(2) && test_facility(75))
|
||||||
|
|
||||||
if (stfle(facility_list, 2) < 2)
|
|
||||||
return;
|
|
||||||
if ((facility_list[0] & (1ULL << 61)) &&
|
|
||||||
(facility_list[1] & (1ULL << 52)))
|
|
||||||
store_indication = 0xc00;
|
store_indication = 0xc00;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -154,14 +154,7 @@ static inline int ap_instructions_available(void)
|
||||||
*/
|
*/
|
||||||
static int ap_interrupts_available(void)
|
static int ap_interrupts_available(void)
|
||||||
{
|
{
|
||||||
unsigned long long facility_bits[2];
|
return test_facility(1) && test_facility(2);
|
||||||
|
|
||||||
if (stfle(facility_bits, 2) <= 1)
|
|
||||||
return 0;
|
|
||||||
if (!(facility_bits[0] & (1ULL << 61)) ||
|
|
||||||
!(facility_bits[1] & (1ULL << 62)))
|
|
||||||
return 0;
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
Loading…
Reference in New Issue