Commit 86302ddf authored by Heiko Carstens's avatar Heiko Carstens
Browse files

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: default avatarHeiko Carstens <hca@linux.ibm.com>
parents 12ea976f 48b4790f
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -30,7 +30,7 @@
 */
#if defined(__GCC_ASM_FLAG_OUTPUTS__) && !(IS_ENABLED(CONFIG_CC_ASM_FLAG_OUTPUT_BROKEN))

#define __HAVE_ASM_FLAG_OUTPUTS__
#define __HAVE_ASM_FLAG_OUTPUTS__ 1

#define CC_IPM(sym)
#define CC_OUT(sym, var)	"=@cc" (var)
+44 −3
Original line number Diff line number Diff line
@@ -8,7 +8,10 @@
#include <asm/cmpxchg.h>
#include <asm/march.h>

/* We use the MSB mostly because its available */
/*
 * Use MSB so it is possible to read preempt_count with LLGT which
 * reads the least significant 31 bits with a single instruction.
 */
#define PREEMPT_NEED_RESCHED	0x80000000

/*
@@ -23,7 +26,20 @@
 */
static __always_inline int preempt_count(void)
{
	return READ_ONCE(get_lowcore()->preempt_count) & ~PREEMPT_NEED_RESCHED;
	unsigned long lc_preempt, count;

	BUILD_BUG_ON(sizeof_field(struct lowcore, preempt_count) != sizeof(int));
	lc_preempt = offsetof(struct lowcore, preempt_count);
	/* READ_ONCE(get_lowcore()->preempt_count) & ~PREEMPT_NEED_RESCHED */
	asm_inline(
		ALTERNATIVE("llgt	%[count],%[offzero](%%r0)\n",
			    "llgt	%[count],%[offalt](%%r0)\n",
			    ALT_FEATURE(MFEATURE_LOWCORE))
		: [count] "=d" (count)
		: [offzero] "i" (lc_preempt),
		  [offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS),
		  "m" (((struct lowcore *)0)->preempt_count));
	return count;
}

static __always_inline void preempt_count_set(int pc)
@@ -68,7 +84,17 @@ static __always_inline void __preempt_count_add(int val)
	 */
	if (!IS_ENABLED(CONFIG_PROFILE_ALL_BRANCHES)) {
		if (__builtin_constant_p(val) && (val >= -128) && (val <= 127)) {
			__atomic_add_const(val, &get_lowcore()->preempt_count);
			unsigned long lc_preempt;

			lc_preempt = offsetof(struct lowcore, preempt_count);
			asm_inline(
				ALTERNATIVE("asi	%[offzero](%%r0),%[val]\n",
					    "asi	%[offalt](%%r0),%[val]\n",
					    ALT_FEATURE(MFEATURE_LOWCORE))
				: "+m" (((struct lowcore *)0)->preempt_count)
				: [offzero] "i" (lc_preempt), [val] "i" (val),
				  [offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS)
				: "cc");
			return;
		}
	}
@@ -87,7 +113,22 @@ static __always_inline void __preempt_count_sub(int val)
 */
static __always_inline bool __preempt_count_dec_and_test(void)
{
#ifdef __HAVE_ASM_FLAG_OUTPUTS__
	unsigned long lc_preempt;
	int cc;

	lc_preempt = offsetof(struct lowcore, preempt_count);
	asm_inline(
		ALTERNATIVE("alsi	%[offzero](%%r0),%[val]\n",
			    "alsi	%[offalt](%%r0),%[val]\n",
			    ALT_FEATURE(MFEATURE_LOWCORE))
		: "=@cc" (cc), "+m" (((struct lowcore *)0)->preempt_count)
		: [offzero] "i" (lc_preempt), [val] "i" (-1),
		[offalt] "i" (lc_preempt + LOWCORE_ALT_ADDRESS));
	return (cc == 0) || (cc == 2);
#else
	return __atomic_add_const_and_test(-1, &get_lowcore()->preempt_count);
#endif
}

/*