Skip to content

Commit 94c7755

Browse files
hcahcazx2c4
authored andcommitted
s390/facility: Let test_facility() generate static branch if possible
Let test_facility() generate a branch instruction if the tested facility is a constant, and where the result cannot be evaluated during compile time. The branch instruction defaults to "false" and is patched to nop (branch not taken) if the tested facility is available. This avoids runtime checks and is similar to x86's static_cpu_has() and arm64's alternative_has_cap_likely(). Signed-off-by: Heiko Carstens <[email protected]> Signed-off-by: Jason A. Donenfeld <[email protected]>
1 parent 013e984 commit 94c7755

File tree

1 file changed

+29
-8
lines changed

1 file changed

+29
-8
lines changed

arch/s390/include/asm/facility.h

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
#include <linux/string.h>
1515
#include <linux/types.h>
1616
#include <linux/preempt.h>
17-
17+
#include <asm/alternative.h>
1818
#include <asm/lowcore.h>
1919

2020
#define MAX_FACILITY_BIT (sizeof(stfle_fac_list) * 8)
@@ -39,30 +39,51 @@ static inline void __clear_facility(unsigned long nr, void *facilities)
3939
ptr[nr >> 3] &= ~(0x80 >> (nr & 7));
4040
}
4141

42-
static inline int __test_facility(unsigned long nr, void *facilities)
42+
static __always_inline bool __test_facility(unsigned long nr, void *facilities)
4343
{
4444
unsigned char *ptr;
4545

4646
if (nr >= MAX_FACILITY_BIT)
47-
return 0;
47+
return false;
4848
ptr = (unsigned char *) facilities + (nr >> 3);
4949
return (*ptr & (0x80 >> (nr & 7))) != 0;
5050
}
5151

52+
/*
53+
* __test_facility_constant() generates a single instruction branch. If the
54+
* tested facility is available (likely) the branch is patched into a nop.
55+
*
56+
* Do not use this function unless you know what you are doing. All users are
57+
* supposed to use test_facility() which will do the right thing.
58+
*/
59+
static __always_inline bool __test_facility_constant(unsigned long nr)
60+
{
61+
asm goto(
62+
ALTERNATIVE("brcl 15,%l[l_no]", "brcl 0,0", ALT_FACILITY(%[nr]))
63+
:
64+
: [nr] "i" (nr)
65+
:
66+
: l_no);
67+
return true;
68+
l_no:
69+
return false;
70+
}
71+
5272
/*
5373
* The test_facility function uses the bit ordering where the MSB is bit 0.
5474
* That makes it easier to query facility bits with the bit number as
5575
* documented in the Principles of Operation.
5676
*/
57-
static inline int test_facility(unsigned long nr)
77+
static __always_inline bool test_facility(unsigned long nr)
5878
{
5979
unsigned long facilities_als[] = { FACILITIES_ALS };
6080

61-
if (__builtin_constant_p(nr) && nr < sizeof(facilities_als) * 8) {
62-
if (__test_facility(nr, &facilities_als)) {
63-
if (!__is_defined(__DECOMPRESSOR))
64-
return 1;
81+
if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(nr)) {
82+
if (nr < sizeof(facilities_als) * 8) {
83+
if (__test_facility(nr, &facilities_als))
84+
return true;
6585
}
86+
return __test_facility_constant(nr);
6687
}
6788
return __test_facility(nr, &stfle_fac_list);
6889
}

0 commit comments

Comments
 (0)