x86/apic: Unify duplicated local apic timer clockevent initialization
authorJacob Pan <jacob.jun.pan@linux.intel.com>
Thu, 25 Apr 2019 17:27:52 +0000 (10:27 -0700)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 25 Apr 2019 18:54:21 +0000 (20:54 +0200)
Local APIC timer clockevent parameters can be calculated based on platform
specific methods. However the code is mostly duplicated with the interrupt
based calibration. The commit which increased the max_delta parameter
updated only one place and made the implementations diverge.

Unify it to prevent further damage.

[ tglx: Rename function to lapic_init_clockevent() and adjust changelog a bit ]

Fixes: 4aed89d6b515 ("x86, lapic-timer: Increase the max_delta to 31 bits")
Reported-by: Daniel Drake <drake@endlessm.com>
Signed-off-by: Jacob Pan <jacob.jun.pan@linux.intel.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Len Brown <lenb@kernel.org>
Link: https://lkml.kernel.org/r/1556213272-63568-1-git-send-email-jacob.jun.pan@linux.intel.com
arch/x86/kernel/apic/apic.c

index b7bcdd7..ab6af77 100644 (file)
@@ -802,6 +802,24 @@ calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc)
        return 0;
 }
 
+static int __init lapic_init_clockevent(void)
+{
+       if (!lapic_timer_frequency)
+               return -1;
+
+       /* Calculate the scaled math multiplication factor */
+       lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
+                                       TICK_NSEC, lapic_clockevent.shift);
+       lapic_clockevent.max_delta_ns =
+               clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
+       lapic_clockevent.max_delta_ticks = 0x7FFFFFFF;
+       lapic_clockevent.min_delta_ns =
+               clockevent_delta2ns(0xF, &lapic_clockevent);
+       lapic_clockevent.min_delta_ticks = 0xF;
+
+       return 0;
+}
+
 static int __init calibrate_APIC_clock(void)
 {
        struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
@@ -810,25 +828,21 @@ static int __init calibrate_APIC_clock(void)
        long delta, deltatsc;
        int pm_referenced = 0;
 
-       /**
-        * check if lapic timer has already been calibrated by platform
-        * specific routine, such as tsc calibration code. if so, we just fill
+       if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
+               return 0;
+
+       /*
+        * Check if lapic timer has already been calibrated by platform
+        * specific routine, such as tsc calibration code. If so just fill
         * in the clockevent structure and return.
         */
-
-       if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) {
-               return 0;
-       } else if (lapic_timer_frequency) {
+       if (!lapic_init_clockevent()) {
                apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
-                               lapic_timer_frequency);
-               lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
-                                       TICK_NSEC, lapic_clockevent.shift);
-               lapic_clockevent.max_delta_ns =
-                       clockevent_delta2ns(0x7FFFFF, &lapic_clockevent);
-               lapic_clockevent.max_delta_ticks = 0x7FFFFF;
-               lapic_clockevent.min_delta_ns =
-                       clockevent_delta2ns(0xF, &lapic_clockevent);
-               lapic_clockevent.min_delta_ticks = 0xF;
+                           lapic_timer_frequency);
+               /*
+                * Direct calibration methods must have an always running
+                * local APIC timer, no need for broadcast timer.
+                */
                lapic_clockevent.features &= ~CLOCK_EVT_FEAT_DUMMY;
                return 0;
        }
@@ -869,17 +883,8 @@ static int __init calibrate_APIC_clock(void)
        pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1,
                                        &delta, &deltatsc);
 
-       /* Calculate the scaled math multiplication factor */
-       lapic_clockevent.mult = div_sc(delta, TICK_NSEC * LAPIC_CAL_LOOPS,
-                                      lapic_clockevent.shift);
-       lapic_clockevent.max_delta_ns =
-               clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
-       lapic_clockevent.max_delta_ticks = 0x7FFFFFFF;
-       lapic_clockevent.min_delta_ns =
-               clockevent_delta2ns(0xF, &lapic_clockevent);
-       lapic_clockevent.min_delta_ticks = 0xF;
-
        lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
+       lapic_init_clockevent();
 
        apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
        apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);