Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 14375bc4 authored by Martin Schwidefsky's avatar Martin Schwidefsky Committed by Martin Schwidefsky
Browse files

[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: default avatarMartin Schwidefsky <schwidefsky@de.ibm.com>
parent eca577ef
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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) {
+8 −3
Original line number Diff line number Diff line
@@ -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 */
+12 −21
Original line number Diff line number Diff line
@@ -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)
+29 −11
Original line number Diff line number Diff line
@@ -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();
+7 −12
Original line number Diff line number Diff line
@@ -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))))
	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.
Loading