]> www.infradead.org Git - users/dwmw2/linux.git/commitdiff
i8253: Disable PIT timer 0 when not in use
authorDavid Woodhouse <dwmw@amazon.co.uk>
Thu, 1 Aug 2024 16:16:08 +0000 (17:16 +0100)
committerDavid Woodhouse <dwmw@amazon.co.uk>
Fri, 2 Aug 2024 14:52:56 +0000 (15:52 +0100)
Leaving the PIT interrupt running can cause noticeable steal time for
virtual guests. The VMM generally has a timer which toggles the IRQ input
to the PIC and I/O APIC, which takes CPU time away from the guest. Even
on real hardware, running the counter may use power needlessly (albeit
not much).

Make sure it's turned off if it isn't going to be used.

Signed-off-by: David Woodhouse <dwmw@amazon.co.uk>
arch/x86/kernel/i8253.c
drivers/clocksource/i8253.c
include/linux/i8253.h

index 2b7999a1a50a83b07084e93903786e15479684b8..80e262bb627fe1d28fa670c9c596696f7f57039d 100644 (file)
@@ -8,6 +8,7 @@
 #include <linux/timex.h>
 #include <linux/i8253.h>
 
+#include <asm/hypervisor.h>
 #include <asm/apic.h>
 #include <asm/hpet.h>
 #include <asm/time.h>
@@ -39,9 +40,15 @@ static bool __init use_pit(void)
 
 bool __init pit_timer_init(void)
 {
-       if (!use_pit())
+       if (!use_pit()) {
+               /*
+                * Don't just ignore the PIT. Ensure it's stopped, because
+                * VMMs otherwise steal CPU time just to pointlessly waggle
+                * the (masked) IRQ.
+                */
+               clockevent_i8253_disable();
                return false;
-
+       }
        clockevent_i8253_init(true);
        global_clock_event = &i8253_clockevent;
        return true;
index d4350bb10b83a26aa1c9a56555ff8a20e949148a..cb215e6f2e8344570f909f03de32a58a3630cb03 100644 (file)
@@ -108,11 +108,8 @@ int __init clocksource_i8253_init(void)
 #endif
 
 #ifdef CONFIG_CLKEVT_I8253
-static int pit_shutdown(struct clock_event_device *evt)
+void clockevent_i8253_disable(void)
 {
-       if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt))
-               return 0;
-
        raw_spin_lock(&i8253_lock);
 
        outb_p(0x30, PIT_MODE);
@@ -123,6 +120,14 @@ static int pit_shutdown(struct clock_event_device *evt)
        }
 
        raw_spin_unlock(&i8253_lock);
+}
+
+static int pit_shutdown(struct clock_event_device *evt)
+{
+       if (!clockevent_state_oneshot(evt) && !clockevent_state_periodic(evt))
+               return 0;
+
+       clockevent_i8253_disable();
        return 0;
 }
 
index 8336b2f6f834627c462a0add39f4502aecfb5ed6..bf169cfef7f12d30ab78b7ced2c22c61f974f19a 100644 (file)
@@ -24,6 +24,7 @@ extern raw_spinlock_t i8253_lock;
 extern bool i8253_clear_counter_on_shutdown;
 extern struct clock_event_device i8253_clockevent;
 extern void clockevent_i8253_init(bool oneshot);
+extern void clockevent_i8253_disable(void);
 
 extern void setup_pit_timer(void);