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);
}
/**