Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

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 <hca@linux.ibm.com>
Signed-off-by: Jason A. Donenfeld <Jason@zx2c4.com>

authored by

Heiko Carstens and committed by
Jason A. Donenfeld
94c7755b 013e9843

+29 -8
+29 -8
arch/s390/include/asm/facility.h
··· 14 14 #include <linux/string.h> 15 15 #include <linux/types.h> 16 16 #include <linux/preempt.h> 17 - 17 + #include <asm/alternative.h> 18 18 #include <asm/lowcore.h> 19 19 20 20 #define MAX_FACILITY_BIT (sizeof(stfle_fac_list) * 8) ··· 39 39 ptr[nr >> 3] &= ~(0x80 >> (nr & 7)); 40 40 } 41 41 42 - static inline int __test_facility(unsigned long nr, void *facilities) 42 + static __always_inline bool __test_facility(unsigned long nr, void *facilities) 43 43 { 44 44 unsigned char *ptr; 45 45 46 46 if (nr >= MAX_FACILITY_BIT) 47 - return 0; 47 + return false; 48 48 ptr = (unsigned char *) facilities + (nr >> 3); 49 49 return (*ptr & (0x80 >> (nr & 7))) != 0; 50 + } 51 + 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; 50 70 } 51 71 52 72 /* ··· 74 54 * That makes it easier to query facility bits with the bit number as 75 55 * documented in the Principles of Operation. 76 56 */ 77 - static inline int test_facility(unsigned long nr) 57 + static __always_inline bool test_facility(unsigned long nr) 78 58 { 79 59 unsigned long facilities_als[] = { FACILITIES_ALS }; 80 60 81 - if (__builtin_constant_p(nr) && nr < sizeof(facilities_als) * 8) { 82 - if (__test_facility(nr, &facilities_als)) { 83 - if (!__is_defined(__DECOMPRESSOR)) 84 - return 1; 61 + if (!__is_defined(__DECOMPRESSOR) && __builtin_constant_p(nr)) { 62 + if (nr < sizeof(facilities_als) * 8) { 63 + if (__test_facility(nr, &facilities_als)) 64 + return true; 85 65 } 66 + return __test_facility_constant(nr); 86 67 } 87 68 return __test_facility(nr, &stfle_fac_list); 88 69 }