Merge tag 'for-linus-2021-01-24' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / arch / x86 / hyperv / hv_init.c
index 4638a52d8eaeae7419a2881e0452237a7251f9e6..6375967a8244dc4e6777d8ff95de1be33ea77e06 100644 (file)
@@ -315,6 +315,25 @@ static struct syscore_ops hv_syscore_ops = {
        .resume         = hv_resume,
 };
 
+static void (* __initdata old_setup_percpu_clockev)(void);
+
+static void __init hv_stimer_setup_percpu_clockev(void)
+{
+       /*
+        * Ignore any errors in setting up stimer clockevents
+        * as we can run with the LAPIC timer as a fallback.
+        */
+       (void)hv_stimer_alloc();
+
+       /*
+        * Still register the LAPIC timer, because the direct-mode STIMER is
+        * not supported by old versions of Hyper-V. This also allows users
+        * to switch to LAPIC timer via /sys, if they want to.
+        */
+       if (old_setup_percpu_clockev)
+               old_setup_percpu_clockev();
+}
+
 /*
  * This function is to be invoked early in the boot sequence after the
  * hypervisor has been detected.
@@ -393,10 +412,14 @@ void __init hyperv_init(void)
        wrmsrl(HV_X64_MSR_HYPERCALL, hypercall_msr.as_uint64);
 
        /*
-        * Ignore any errors in setting up stimer clockevents
-        * as we can run with the LAPIC timer as a fallback.
+        * hyperv_init() is called before LAPIC is initialized: see
+        * apic_intr_mode_init() -> x86_platform.apic_post_init() and
+        * apic_bsp_setup() -> setup_local_APIC(). The direct-mode STIMER
+        * depends on LAPIC, so hv_stimer_alloc() should be called from
+        * x86_init.timers.setup_percpu_clockev.
         */
-       (void)hv_stimer_alloc();
+       old_setup_percpu_clockev = x86_init.timers.setup_percpu_clockev;
+       x86_init.timers.setup_percpu_clockev = hv_stimer_setup_percpu_clockev;
 
        hv_apic_init();