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.

Merge branch 'preempt'

Heiko Carstens says:

====================

The option to select PREEMPT_NONE will go away for all architectures which
support PREEMPT_LAZY [1]. Until now all distributions provide kernels built
with PREEMPT_NONE enabled for s390. In particular this means that all
preempt_disable() / preempt_enable() pairs are optimized away during
compile time.

With PREEMPT_LAZY this is not the case. Switching to PREEMPT_LAZY leads
to a kernel image size increase of ~218kb (defconfig, gcc15).

s390 provides optimized preempt primitives, however there is still room for
improvement. Since support for relocatable lowcore was added access to
preempt_count in lowcore requires an extra call of get_lowcore(), which
generates an extra instruction. Also all instructions have to use a base
register which is not zero to access preempt_count.

Address this by adding a couple of inline assemblies with alternatives.

This generates better code and reduces the size of a PREEMPT_LAZY built
kernel image by ~58kb.

[1] https://lore.kernel.org/all/20251219101502.GB1132199@noisy.programming.kicks-ass.net/

====================

Signed-off-by: Heiko Carstens <hca@linux.ibm.com>

+45 -4
+1 -1
arch/s390/include/asm/asm.h
··· 30 30 */ 31 31 #if defined(__GCC_ASM_FLAG_OUTPUTS__) && !(IS_ENABLED(CONFIG_CC_ASM_FLAG_OUTPUT_BROKEN)) 32 32 33 - #define __HAVE_ASM_FLAG_OUTPUTS__ 33 + #define __HAVE_ASM_FLAG_OUTPUTS__ 1 34 34 35 35 #define CC_IPM(sym) 36 36 #define CC_OUT(sym, var) "=@cc" (var)
+44 -3
arch/s390/include/asm/preempt.h
··· 8 8 #include <asm/cmpxchg.h> 9 9 #include <asm/march.h> 10 10 11 - /* We use the MSB mostly because its available */ 11 + /* 12 + * Use MSB so it is possible to read preempt_count with LLGT which 13 + * reads the least significant 31 bits with a single instruction. 14 + */ 12 15 #define PREEMPT_NEED_RESCHED 0x80000000 13 16 14 17 /* ··· 26 23 */ 27 24 static __always_inline int preempt_count(void) 28 25 { 29 - return READ_ONCE(get_lowcore()->preempt_count) & ~PREEMPT_NEED_RESCHED; 26 + unsigned long lc_preempt, count; 27 + 28 + BUILD_BUG_ON(sizeof_field(struct lowcore, preempt_count) != sizeof(int)); 29 + lc_preempt = offsetof(struct lowcore, preempt_count); 30 + /* READ_ONCE(get_lowcore()->preempt_count) & ~PREEMPT_NEED_RESCHED */ 31 + asm_inline( 32 + ALTERNATIVE("llgt %[count],%[offzero](%%r0)\n", 33 + "llgt %[count],%[offalt](%%r0)\n", 34 + ALT_FEATURE(MFEATURE_LOWCORE)) 35 + : [count] "=d" (count) 36 + : [offzero] "i" (lc_preempt), 37 + [offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS), 38 + "m" (((struct lowcore *)0)->preempt_count)); 39 + return count; 30 40 } 31 41 32 42 static __always_inline void preempt_count_set(int pc) ··· 84 68 */ 85 69 if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES)) { 86 70 if (__builtin_constant_p(val) && (val >= -128) && (val <= 127)) { 87 - __atomic_add_const(val, &get_lowcore()->preempt_count); 71 + unsigned long lc_preempt; 72 + 73 + lc_preempt = offsetof(struct lowcore, preempt_count); 74 + asm_inline( 75 + ALTERNATIVE("asi %[offzero](%%r0),%[val]\n", 76 + "asi %[offalt](%%r0),%[val]\n", 77 + ALT_FEATURE(MFEATURE_LOWCORE)) 78 + : "+m" (((struct lowcore *)0)->preempt_count) 79 + : [offzero] "i" (lc_preempt), [val] "i" (val), 80 + [offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS) 81 + : "cc"); 88 82 return; 89 83 } 90 84 } ··· 113 87 */ 114 88 static __always_inline bool __preempt_count_dec_and_test(void) 115 89 { 90 + #ifdef __HAVE_ASM_FLAG_OUTPUTS__ 91 + unsigned long lc_preempt; 92 + int cc; 93 + 94 + lc_preempt = offsetof(struct lowcore, preempt_count); 95 + asm_inline( 96 + ALTERNATIVE("alsi %[offzero](%%r0),%[val]\n", 97 + "alsi %[offalt](%%r0),%[val]\n", 98 + ALT_FEATURE(MFEATURE_LOWCORE)) 99 + : "=@cc" (cc), "+m" (((struct lowcore *)0)->preempt_count) 100 + : [offzero] "i" (lc_preempt), [val] "i" (-1), 101 + [offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS)); 102 + return (cc == 0) || (cc == 2); 103 + #else 116 104 return __atomic_add_const_and_test(-1, &get_lowcore()->preempt_count); 105 + #endif 117 106 } 118 107 119 108 /*