Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86: use cpu_khz for loops_per_jiffy calculation

On the x86 platform we can use the value of tsc_khz computed during tsc
calibration to calculate the loops_per_jiffy value. Its very important
to keep the error in lpj values to minimum as any error in that may
result in kernel panic in check_timer. In virtualization environment, On
a highly overloaded host the guest delay calibration may sometimes
result in errors beyond the ~50% that timer_irq_works can handle,
resulting in the guest panicking.

Does some formating changes to lpj_setup code to now have a single
printk to print the bogomips value.

We do this only for the boot processor because the AP's can have
different base frequencies or the BIOS might boot a AP at a different
frequency.

Signed-off-by: Alok N Kataria <akataria@vmware.com>
Cc: Arjan van de Ven <arjan@infradead.org>
Cc: Daniel Hecht <dhecht@vmware.com>
Cc: Tim Mann <mann@vmware.com>
Cc: Zach Amsden <zach@vmware.com>
Cc: Sahil Rihan <srihan@vmware.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>

authored by

Alok Kataria and committed by
Ingo Molnar
3da757da e01b70ef

+27 -17
+2
arch/x86/kernel/time_64.c
··· 123 123 (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)) 124 124 cpu_khz = calculate_cpu_khz(); 125 125 126 + lpj_tsc = ((unsigned long)tsc_khz * 1000)/HZ; 127 + 126 128 if (unsynchronized_tsc()) 127 129 mark_tsc_unstable("TSCs unsynchronized"); 128 130
+5
arch/x86/kernel/tsc_32.c
··· 401 401 void __init tsc_init(void) 402 402 { 403 403 int cpu; 404 + u64 lpj; 404 405 405 406 if (!cpu_has_tsc || tsc_disabled) { 406 407 /* Disable the TSC in case of !cpu_has_tsc */ ··· 421 420 tsc_disabled = 1; 422 421 return; 423 422 } 423 + 424 + lpj = ((u64)tsc_khz * 1000); 425 + do_div(lpj, HZ); 426 + lpj_tsc = lpj; 424 427 425 428 printk("Detected %lu.%03lu MHz processor.\n", 426 429 (unsigned long)cpu_khz / 1000,
+1
include/linux/delay.h
··· 41 41 #define ndelay(x) ndelay(x) 42 42 #endif 43 43 44 + extern unsigned long lpj_tsc; 44 45 void calibrate_delay(void); 45 46 void msleep(unsigned int msecs); 46 47 unsigned long msleep_interruptible(unsigned int msecs);
+19 -17
init/calibrate.c
··· 8 8 #include <linux/delay.h> 9 9 #include <linux/init.h> 10 10 #include <linux/timex.h> 11 + #include <linux/smp.h> 11 12 13 + unsigned long lpj_tsc; 12 14 unsigned long preset_lpj; 13 15 static int __init lpj_setup(char *str) 14 16 { ··· 110 108 * This is the number of bits of precision for the loops_per_jiffy. Each 111 109 * bit takes on average 1.5/HZ seconds. This (like the original) is a little 112 110 * better than 1% 111 + * For the boot cpu we can skip the delay calibration and assign it a value 112 + * calculated based on the tsc frequency. 113 + * For the rest of the CPUs we cannot assume that the tsc frequency is same as 114 + * the cpu frequency, hence do the calibration for those. 113 115 */ 114 116 #define LPS_PREC 8 115 117 ··· 124 118 125 119 if (preset_lpj) { 126 120 loops_per_jiffy = preset_lpj; 127 - printk("Calibrating delay loop (skipped)... " 128 - "%lu.%02lu BogoMIPS preset\n", 129 - loops_per_jiffy/(500000/HZ), 130 - (loops_per_jiffy/(5000/HZ)) % 100); 121 + printk(KERN_INFO 122 + "Calibrating delay loop (skipped) preset value.. "); 123 + } else if ((smp_processor_id() == 0) && lpj_tsc) { 124 + loops_per_jiffy = lpj_tsc; 125 + printk(KERN_INFO 126 + "Calibrating delay loop (skipped), " 127 + "using tsc calculated value.. "); 131 128 } else if ((loops_per_jiffy = calibrate_delay_direct()) != 0) { 132 - printk("Calibrating delay using timer specific routine.. "); 133 - printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", 134 - loops_per_jiffy/(500000/HZ), 135 - (loops_per_jiffy/(5000/HZ)) % 100, 136 - loops_per_jiffy); 129 + printk(KERN_INFO 130 + "Calibrating delay using timer specific routine.. "); 137 131 } else { 138 132 loops_per_jiffy = (1<<12); 139 133 140 - printk(KERN_DEBUG "Calibrating delay loop... "); 134 + printk(KERN_INFO "Calibrating delay loop... "); 141 135 while ((loops_per_jiffy <<= 1) != 0) { 142 136 /* wait for "start of" clock tick */ 143 137 ticks = jiffies; ··· 167 161 if (jiffies != ticks) /* longer than 1 tick */ 168 162 loops_per_jiffy &= ~loopbit; 169 163 } 170 - 171 - /* Round the value and print it */ 172 - printk("%lu.%02lu BogoMIPS (lpj=%lu)\n", 173 - loops_per_jiffy/(500000/HZ), 174 - (loops_per_jiffy/(5000/HZ)) % 100, 175 - loops_per_jiffy); 176 164 } 177 - 165 + printk(KERN_INFO "%lu.%02lu BogoMIPS (lpj=%lu)\n", 166 + loops_per_jiffy/(500000/HZ), 167 + (loops_per_jiffy/(5000/HZ)) % 100, loops_per_jiffy); 178 168 }