]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
x86: reduce clock calibration time during slave cpu startup
authorJack Steiner <steiner@sgi.com>
Wed, 16 Nov 2011 23:41:04 +0000 (10:41 +1100)
committerStephen Rothwell <sfr@canb.auug.org.au>
Tue, 29 Nov 2011 03:37:14 +0000 (14:37 +1100)
Reduce the startup time for slave cpus.

Adds hooks for an arch-specific function for clock calibration.  These
hooks are used on x86.  If a newly started cpu has the same phys_proc_id
as a core already active, uses the TSC for the delay loop and has a
CONSTANT_TSC, use the already-calculated value of loops_per_jiffy.

This patch reduces the time required to start slave cpus on a 4096 cpu
system from: 465 sec OLD 62 sec NEW

This reduces boot time on a 4096p system by almost 7 minutes.  Nice...

[akpm@linux-foundation.org: fix CONFIG_SMP=n build]
Signed-off-by: Jack Steiner <steiner@sgi.com>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: John Stultz <john.stultz@linaro.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
arch/x86/kernel/smpboot.c
arch/x86/kernel/tsc.c
init/calibrate.c

index 9f548cb4a958309fd04ffcc12535e5100b5787ee..00eef55c8327916597aef8bfa39c14e4c4a45be5 100644 (file)
@@ -207,22 +207,28 @@ static void __cpuinit smp_callin(void)
         * Need to setup vector mappings before we enable interrupts.
         */
        setup_vector_irq(smp_processor_id());
+
+       /*
+        * Save our processor parameters. Note: this information
+        * is needed for clock calibration.
+        */
+       smp_store_cpu_info(cpuid);
+
        /*
         * Get our bogomips.
+        * Update loops_per_jiffy in cpu_data. Previous call to
+        * smp_store_cpu_info() stored a value that is close but not as
+        * accurate as the value just calculated.
         *
         * Need to enable IRQs because it can take longer and then
         * the NMI watchdog might kill us.
         */
        local_irq_enable();
        calibrate_delay();
+       cpu_data(cpuid).loops_per_jiffy = loops_per_jiffy;
        local_irq_disable();
        pr_debug("Stack at about %p\n", &cpuid);
 
-       /*
-        * Save our processor parameters
-        */
-       smp_store_cpu_info(cpuid);
-
        /*
         * This must be done before setting cpu_online_mask
         * or calling notify_cpu_starting.
index db483369f10be5c07bfe8564a1a073c34ffb22fb..490fb330be87bae0239f523cfd20286e33edf9f6 100644 (file)
@@ -995,3 +995,23 @@ void __init tsc_init(void)
        check_system_tsc_reliable();
 }
 
+#ifdef CONFIG_SMP
+/*
+ * If we have a constant TSC and are using the TSC for the delay loop,
+ * we can skip clock calibration if another cpu in the same socket has already
+ * been calibrated. This assumes that CONSTANT_TSC applies to all
+ * cpus in the socket - this should be a safe assumption.
+ */
+unsigned long __cpuinit calibrate_delay_is_known(void)
+{
+       int i, cpu = smp_processor_id();
+
+       if (!tsc_disabled && !cpu_has(&cpu_data(cpu), X86_FEATURE_CONSTANT_TSC))
+               return 0;
+
+       for_each_online_cpu(i)
+               if (cpu_data(i).phys_proc_id == cpu_data(cpu).phys_proc_id)
+                       return cpu_data(i).loops_per_jiffy;
+       return 0;
+}
+#endif
index 24df7976816c6ca99f3403f97444f8e49f69a0a7..5f117ca9e0694488765ed0d4c0ea70baae7e6a04 100644 (file)
@@ -246,6 +246,19 @@ recalibrate:
 
 static DEFINE_PER_CPU(unsigned long, cpu_loops_per_jiffy) = { 0 };
 
+/*
+ * Check if cpu calibration delay is already known. For example,
+ * some processors with multi-core sockets may have all cores
+ * with the same calibration delay.
+ *
+ * Architectures should override this function if a faster calibration
+ * method is available.
+ */
+unsigned long __attribute__((weak)) __cpuinit calibrate_delay_is_known(void)
+{
+       return 0;
+}
+
 void __cpuinit calibrate_delay(void)
 {
        unsigned long lpj;
@@ -265,6 +278,8 @@ void __cpuinit calibrate_delay(void)
                lpj = lpj_fine;
                pr_info("Calibrating delay loop (skipped), "
                        "value calculated using timer frequency.. ");
+       } else if ((lpj = calibrate_delay_is_known())) {
+               ;
        } else if ((lpj = calibrate_delay_direct()) != 0) {
                if (!printed)
                        pr_info("Calibrating delay using timer "