Skip to content

Commit

Permalink
sched/idle: Conditionally handle tick broadcast in default_idle_call()
Browse files Browse the repository at this point in the history
The x86 architecture has an idle routine for AMD CPUs which are affected
by erratum 400. On the affected CPUs the local APIC timer stops in the
C1E halt state.

It therefore requires tick broadcasting. The invocation of
tick_broadcast_enter()/exit() from this function violates the RCU
constraints because it can end up in lockdep or tracing, which
rightfully triggers a warning.

tick_broadcast_enter()/exit() must be invoked before ct_cpuidle_enter()
and after ct_cpuidle_exit() in default_idle_call().

Add a static branch conditional invocation of tick_broadcast_enter()/exit()
into this function to allow X86 to replace the AMD specific idle code. It's
guarded by a config switch which will be selected by x86. Otherwise it's
a NOOP.

Reported-by: Borislav Petkov <bp@alien8.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Link: https://lore.kernel.org/r/20240229142248.266708822@linutronix.de
  • Loading branch information
Thomas Gleixner authored and Borislav Petkov (AMD) committed Mar 1, 2024
1 parent 44c7682 commit 2be2a19
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 0 deletions.
2 changes: 2 additions & 0 deletions include/linux/cpu.h
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,8 @@ void arch_cpu_idle(void);
void arch_cpu_idle_prepare(void);
void arch_cpu_idle_enter(void);
void arch_cpu_idle_exit(void);
void arch_tick_broadcast_enter(void);
void arch_tick_broadcast_exit(void);
void __noreturn arch_cpu_idle_dead(void);

#ifdef CONFIG_ARCH_HAS_CPU_FINALIZE_INIT
Expand Down
3 changes: 3 additions & 0 deletions include/linux/tick.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include <linux/cpumask.h>
#include <linux/sched.h>
#include <linux/rcupdate.h>
#include <linux/static_key.h>

#ifdef CONFIG_GENERIC_CLOCKEVENTS
extern void __init tick_init(void);
Expand Down Expand Up @@ -63,6 +64,8 @@ enum tick_broadcast_state {
TICK_BROADCAST_ENTER,
};

extern struct static_key_false arch_needs_tick_broadcast;

#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST
extern void tick_broadcast_control(enum tick_broadcast_mode mode);
#else
Expand Down
21 changes: 21 additions & 0 deletions kernel/sched/idle.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,25 @@ void __weak arch_cpu_idle(void)
cpu_idle_force_poll = 1;
}

#ifdef CONFIG_GENERIC_CLOCKEVENTS_BROADCAST_IDLE
DEFINE_STATIC_KEY_FALSE(arch_needs_tick_broadcast);

static inline void cond_tick_broadcast_enter(void)
{
if (static_branch_unlikely(&arch_needs_tick_broadcast))
tick_broadcast_enter();
}

static inline void cond_tick_broadcast_exit(void)
{
if (static_branch_unlikely(&arch_needs_tick_broadcast))
tick_broadcast_exit();
}
#else
static inline void cond_tick_broadcast_enter(void) { }
static inline void cond_tick_broadcast_exit(void) { }
#endif

/**
* default_idle_call - Default CPU idle routine.
*
Expand All @@ -90,6 +109,7 @@ void __cpuidle default_idle_call(void)
{
instrumentation_begin();
if (!current_clr_polling_and_test()) {
cond_tick_broadcast_enter();
trace_cpu_idle(1, smp_processor_id());
stop_critical_timings();

Expand All @@ -99,6 +119,7 @@ void __cpuidle default_idle_call(void)

start_critical_timings();
trace_cpu_idle(PWR_EVENT_EXIT, smp_processor_id());
cond_tick_broadcast_exit();
}
local_irq_enable();
instrumentation_end();
Expand Down
5 changes: 5 additions & 0 deletions kernel/time/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ config GENERIC_CLOCKEVENTS_BROADCAST
bool
depends on GENERIC_CLOCKEVENTS

# Handle broadcast in default_idle_call()
config GENERIC_CLOCKEVENTS_BROADCAST_IDLE
bool
depends on GENERIC_CLOCKEVENTS_BROADCAST

# Automatically adjust the min. reprogramming time for
# clock event device
config GENERIC_CLOCKEVENTS_MIN_ADJUST
Expand Down

0 comments on commit 2be2a19

Please sign in to comment.