Skip to content

Commit 9799238

Browse files
KAGA-KOKOIngo Molnar
authored andcommitted
x86/timer: Don't skip PIT setup when APIC is disabled or in legacy mode
Tony reported a boot regression caused by the recent workaround for systems which have a disabled (clock gate off) PIT. On his machine the kernel fails to initialize the PIT because apic_needs_pit() does not take into account whether the local APIC interrupt delivery mode will actually allow to setup and use the local APIC timer. This should be easy to reproduce with acpi=off on the command line which also disables HPET. Due to the way the PIT/HPET and APIC setup ordering works (APIC setup can require working PIT/HPET) the information is not available at the point where apic_needs_pit() makes this decision. To address this, split out the interrupt mode selection from apic_intr_mode_init(), invoke the selection before making the decision whether PIT is required or not, and add the missing checks into apic_needs_pit(). Fixes: c8c4076 ("x86/timer: Skip PIT initialization on modern chipsets") Reported-by: Anthony Buckley <[email protected]> Tested-by: Anthony Buckley <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Signed-off-by: Ingo Molnar <[email protected]> Cc: Daniel Drake <[email protected]> Link: https://bugzilla.kernel.org/show_bug.cgi?id=206125 Link: https://lore.kernel.org/r/[email protected]
1 parent 6bd3357 commit 9799238

File tree

6 files changed

+34
-7
lines changed

6 files changed

+34
-7
lines changed

arch/x86/include/asm/apic.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ extern void apic_soft_disable(void);
140140
extern void lapic_shutdown(void);
141141
extern void sync_Arb_IDs(void);
142142
extern void init_bsp_APIC(void);
143+
extern void apic_intr_mode_select(void);
143144
extern void apic_intr_mode_init(void);
144145
extern void init_apic_mappings(void);
145146
void register_lapic_address(unsigned long address);
@@ -188,6 +189,7 @@ static inline void disable_local_APIC(void) { }
188189
# define setup_secondary_APIC_clock x86_init_noop
189190
static inline void lapic_update_tsc_freq(void) { }
190191
static inline void init_bsp_APIC(void) { }
192+
static inline void apic_intr_mode_select(void) { }
191193
static inline void apic_intr_mode_init(void) { }
192194
static inline void lapic_assign_system_vectors(void) { }
193195
static inline void lapic_assign_legacy_vector(unsigned int i, bool r) { }

arch/x86/include/asm/x86_init.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,12 +51,14 @@ struct x86_init_resources {
5151
* are set up.
5252
* @intr_init: interrupt init code
5353
* @trap_init: platform specific trap setup
54+
* @intr_mode_select: interrupt delivery mode selection
5455
* @intr_mode_init: interrupt delivery mode setup
5556
*/
5657
struct x86_init_irqs {
5758
void (*pre_vector_init)(void);
5859
void (*intr_init)(void);
5960
void (*trap_init)(void);
61+
void (*intr_mode_select)(void);
6062
void (*intr_mode_init)(void);
6163
};
6264

arch/x86/kernel/apic/apic.c

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -830,8 +830,17 @@ bool __init apic_needs_pit(void)
830830
if (!tsc_khz || !cpu_khz)
831831
return true;
832832

833-
/* Is there an APIC at all? */
834-
if (!boot_cpu_has(X86_FEATURE_APIC))
833+
/* Is there an APIC at all or is it disabled? */
834+
if (!boot_cpu_has(X86_FEATURE_APIC) || disable_apic)
835+
return true;
836+
837+
/*
838+
* If interrupt delivery mode is legacy PIC or virtual wire without
839+
* configuration, the local APIC timer wont be set up. Make sure
840+
* that the PIT is initialized.
841+
*/
842+
if (apic_intr_mode == APIC_PIC ||
843+
apic_intr_mode == APIC_VIRTUAL_WIRE_NO_CONFIG)
835844
return true;
836845

837846
/* Virt guests may lack ARAT, but still have DEADLINE */
@@ -1322,7 +1331,7 @@ void __init sync_Arb_IDs(void)
13221331

13231332
enum apic_intr_mode_id apic_intr_mode __ro_after_init;
13241333

1325-
static int __init apic_intr_mode_select(void)
1334+
static int __init __apic_intr_mode_select(void)
13261335
{
13271336
/* Check kernel option */
13281337
if (disable_apic) {
@@ -1384,6 +1393,12 @@ static int __init apic_intr_mode_select(void)
13841393
return APIC_SYMMETRIC_IO;
13851394
}
13861395

1396+
/* Select the interrupt delivery mode for the BSP */
1397+
void __init apic_intr_mode_select(void)
1398+
{
1399+
apic_intr_mode = __apic_intr_mode_select();
1400+
}
1401+
13871402
/*
13881403
* An initial setup of the virtual wire mode.
13891404
*/
@@ -1440,8 +1455,6 @@ void __init apic_intr_mode_init(void)
14401455
{
14411456
bool upmode = IS_ENABLED(CONFIG_UP_LATE_INIT);
14421457

1443-
apic_intr_mode = apic_intr_mode_select();
1444-
14451458
switch (apic_intr_mode) {
14461459
case APIC_PIC:
14471460
pr_info("APIC: Keep in PIC mode(8259)\n");

arch/x86/kernel/time.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,18 @@ void __init hpet_time_init(void)
9191

9292
static __init void x86_late_time_init(void)
9393
{
94+
/*
95+
* Before PIT/HPET init, select the interrupt mode. This is required
96+
* to make the decision whether PIT should be initialized correct.
97+
*/
98+
x86_init.irqs.intr_mode_select();
99+
100+
/* Setup the legacy timers */
94101
x86_init.timers.timer_init();
102+
95103
/*
96-
* After PIT/HPET timers init, select and setup
97-
* the final interrupt mode for delivering IRQs.
104+
* After PIT/HPET timers init, set up the final interrupt mode for
105+
* delivering IRQs.
98106
*/
99107
x86_init.irqs.intr_mode_init();
100108
tsc_init();

arch/x86/kernel/x86_init.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ struct x86_init_ops x86_init __initdata = {
8080
.pre_vector_init = init_ISA_irqs,
8181
.intr_init = native_init_IRQ,
8282
.trap_init = x86_init_noop,
83+
.intr_mode_select = apic_intr_mode_select,
8384
.intr_mode_init = apic_intr_mode_init
8485
},
8586

arch/x86/xen/enlighten_pv.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1205,6 +1205,7 @@ asmlinkage __visible void __init xen_start_kernel(void)
12051205
x86_platform.get_nmi_reason = xen_get_nmi_reason;
12061206

12071207
x86_init.resources.memory_setup = xen_memory_setup;
1208+
x86_init.irqs.intr_mode_select = x86_init_noop;
12081209
x86_init.irqs.intr_mode_init = x86_init_noop;
12091210
x86_init.oem.arch_setup = xen_arch_setup;
12101211
x86_init.oem.banner = xen_banner;

0 commit comments

Comments
 (0)