Blame view
init/calibrate.c
7.9 KB
1da177e4c Linux-2.6.12-rc2 |
1 2 3 4 5 |
/* calibrate.c: default delay calibration * * Excised from init/main.c * Copyright (C) 1991, 1992 Linus Torvalds */ |
cd354f1ae [PATCH] remove ma... |
6 |
#include <linux/jiffies.h> |
1da177e4c Linux-2.6.12-rc2 |
7 8 |
#include <linux/delay.h> #include <linux/init.h> |
941e492bd read_current_time... |
9 |
#include <linux/timex.h> |
3da757daf x86: use cpu_khz ... |
10 |
#include <linux/smp.h> |
7afe1845d init: skip calibr... |
11 |
#include <linux/percpu.h> |
8a9e1b0f5 [PATCH] Platform ... |
12 |
|
f3f3149f3 x86: use cpu_khz ... |
13 |
unsigned long lpj_fine; |
bfe8df3d3 slow down printk ... |
14 |
unsigned long preset_lpj; |
1da177e4c Linux-2.6.12-rc2 |
15 16 17 18 19 20 21 |
static int __init lpj_setup(char *str) { preset_lpj = simple_strtoul(str,NULL,0); return 1; } __setup("lpj=", lpj_setup); |
8a9e1b0f5 [PATCH] Platform ... |
22 23 24 25 26 27 28 29 30 |
#ifdef ARCH_HAS_READ_CURRENT_TIMER /* This routine uses the read_current_timer() routine and gets the * loops per jiffy directly, instead of guessing it using delay(). * Also, this code tries to handle non-maskable asynchronous events * (like SMIs) */ #define DELAY_CALIBRATION_TICKS ((HZ < 100) ? 1 : (HZ/100)) #define MAX_DIRECT_CALIBRATION_RETRIES 5 |
6c81c32f9 calibrate_delay()... |
31 |
static unsigned long __cpuinit calibrate_delay_direct(void) |
8a9e1b0f5 [PATCH] Platform ... |
32 33 34 35 |
{ unsigned long pre_start, start, post_start; unsigned long pre_end, end, post_end; unsigned long start_jiffies; |
f3f3149f3 x86: use cpu_khz ... |
36 37 38 |
unsigned long timer_rate_min, timer_rate_max; unsigned long good_timer_sum = 0; unsigned long good_timer_count = 0; |
d2b463135 init/calibrate.c:... |
39 40 41 |
unsigned long measured_times[MAX_DIRECT_CALIBRATION_RETRIES]; int max = -1; /* index of measured_times with max/min values or not set */ int min = -1; |
8a9e1b0f5 [PATCH] Platform ... |
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
int i; if (read_current_timer(&pre_start) < 0 ) return 0; /* * A simple loop like * while ( jiffies < start_jiffies+1) * start = read_current_timer(); * will not do. As we don't really know whether jiffy switch * happened first or timer_value was read first. And some asynchronous * event can happen between these two events introducing errors in lpj. * * So, we do * 1. pre_start <- When we are sure that jiffy switch hasn't happened * 2. check jiffy switch * 3. start <- timer value before or after jiffy switch * 4. post_start <- When we are sure that jiffy switch has happened * * Note, we don't know anything about order of 2 and 3. * Now, by looking at post_start and pre_start difference, we can * check whether any asynchronous event happened or not */ for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { pre_start = 0; read_current_timer(&start); start_jiffies = jiffies; |
70a062286 fix jiffy calcula... |
70 |
while (time_before_eq(jiffies, start_jiffies + 1)) { |
8a9e1b0f5 [PATCH] Platform ... |
71 72 73 74 75 76 77 |
pre_start = start; read_current_timer(&start); } read_current_timer(&post_start); pre_end = 0; end = post_start; |
70a062286 fix jiffy calcula... |
78 79 |
while (time_before_eq(jiffies, start_jiffies + 1 + DELAY_CALIBRATION_TICKS)) { |
8a9e1b0f5 [PATCH] Platform ... |
80 81 82 83 |
pre_end = end; read_current_timer(&end); } read_current_timer(&post_end); |
f3f3149f3 x86: use cpu_khz ... |
84 85 86 87 |
timer_rate_max = (post_end - pre_start) / DELAY_CALIBRATION_TICKS; timer_rate_min = (pre_end - post_start) / DELAY_CALIBRATION_TICKS; |
8a9e1b0f5 [PATCH] Platform ... |
88 89 |
/* |
f3f3149f3 x86: use cpu_khz ... |
90 |
* If the upper limit and lower limit of the timer_rate is |
8a9e1b0f5 [PATCH] Platform ... |
91 92 |
* >= 12.5% apart, redo calibration. */ |
d2b463135 init/calibrate.c:... |
93 94 95 96 97 98 99 |
if (start >= post_end) printk(KERN_NOTICE "calibrate_delay_direct() ignoring " "timer_rate as we had a TSC wrap around" " start=%lu >=post_end=%lu ", start, post_end); if (start < post_end && pre_start != 0 && pre_end != 0 && |
f3f3149f3 x86: use cpu_khz ... |
100 101 102 |
(timer_rate_max - timer_rate_min) < (timer_rate_max >> 3)) { good_timer_count++; good_timer_sum += timer_rate_max; |
d2b463135 init/calibrate.c:... |
103 104 105 106 107 108 109 |
measured_times[i] = timer_rate_max; if (max < 0 || timer_rate_max > measured_times[max]) max = i; if (min < 0 || timer_rate_max < measured_times[min]) min = i; } else measured_times[i] = 0; |
8a9e1b0f5 [PATCH] Platform ... |
110 |
} |
d2b463135 init/calibrate.c:... |
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
/* * Find the maximum & minimum - if they differ too much throw out the * one with the largest difference from the mean and try again... */ while (good_timer_count > 1) { unsigned long estimate; unsigned long maxdiff; /* compute the estimate */ estimate = (good_timer_sum/good_timer_count); maxdiff = estimate >> 3; /* if range is within 12% let's take it */ if ((measured_times[max] - measured_times[min]) < maxdiff) return estimate; /* ok - drop the worse value and try again... */ good_timer_sum = 0; good_timer_count = 0; if ((measured_times[max] - estimate) < (estimate - measured_times[min])) { printk(KERN_NOTICE "calibrate_delay_direct() dropping " "min bogoMips estimate %d = %lu ", min, measured_times[min]); measured_times[min] = 0; min = max; } else { printk(KERN_NOTICE "calibrate_delay_direct() dropping " "max bogoMips estimate %d = %lu ", max, measured_times[max]); measured_times[max] = 0; max = min; } for (i = 0; i < MAX_DIRECT_CALIBRATION_RETRIES; i++) { if (measured_times[i] == 0) continue; good_timer_count++; good_timer_sum += measured_times[i]; if (measured_times[i] < measured_times[min]) min = i; if (measured_times[i] > measured_times[max]) max = i; } } |
8a9e1b0f5 [PATCH] Platform ... |
159 |
|
d2b463135 init/calibrate.c:... |
160 161 162 163 164 |
printk(KERN_NOTICE "calibrate_delay_direct() failed to get a good " "estimate for loops_per_jiffy. Probably due to long platform " "interrupts. Consider using \"lpj=\" boot option. "); |
8a9e1b0f5 [PATCH] Platform ... |
165 166 167 |
return 0; } #else |
6c81c32f9 calibrate_delay()... |
168 |
static unsigned long __cpuinit calibrate_delay_direct(void) {return 0;} |
8a9e1b0f5 [PATCH] Platform ... |
169 |
#endif |
1da177e4c Linux-2.6.12-rc2 |
170 171 |
/* * This is the number of bits of precision for the loops_per_jiffy. Each |
191e56880 calibrate: home i... |
172 173 |
* time we refine our estimate after the first takes 1.5/HZ seconds, so try * to start with a good estimate. |
3da757daf x86: use cpu_khz ... |
174 |
* For the boot cpu we can skip the delay calibration and assign it a value |
f3f3149f3 x86: use cpu_khz ... |
175 176 |
* calculated based on the timer frequency. * For the rest of the CPUs we cannot assume that the timer frequency is same as |
3da757daf x86: use cpu_khz ... |
177 |
* the cpu frequency, hence do the calibration for those. |
1da177e4c Linux-2.6.12-rc2 |
178 179 |
*/ #define LPS_PREC 8 |
71c696b1d calibrate: extrac... |
180 |
static unsigned long __cpuinit calibrate_delay_converge(void) |
1da177e4c Linux-2.6.12-rc2 |
181 |
{ |
191e56880 calibrate: home i... |
182 |
/* First stage - slowly accelerate to find initial bounds */ |
b1b5f65e5 calibrate: retry ... |
183 |
unsigned long lpj, lpj_base, ticks, loopadd, loopadd_base, chop_limit; |
191e56880 calibrate: home i... |
184 |
int trials = 0, band = 0, trial_in_band = 0; |
71c696b1d calibrate: extrac... |
185 186 |
lpj = (1<<12); |
191e56880 calibrate: home i... |
187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 |
/* wait for "start of" clock tick */ ticks = jiffies; while (ticks == jiffies) ; /* nothing */ /* Go .. */ ticks = jiffies; do { if (++trial_in_band == (1<<band)) { ++band; trial_in_band = 0; } __delay(lpj * band); trials += band; } while (ticks == jiffies); /* * We overshot, so retreat to a clear underestimate. Then estimate * the largest likely undershoot. This defines our chop bounds. */ trials -= band; |
b1b5f65e5 calibrate: retry ... |
207 208 209 210 211 212 |
loopadd_base = lpj * band; lpj_base = lpj * trials; recalibrate: lpj = lpj_base; loopadd = loopadd_base; |
71c696b1d calibrate: extrac... |
213 214 215 |
/* * Do a binary approximation to get lpj set to |
191e56880 calibrate: home i... |
216 |
* equal one clock (up to LPS_PREC bits) |
71c696b1d calibrate: extrac... |
217 |
*/ |
b1b5f65e5 calibrate: retry ... |
218 |
chop_limit = lpj >> LPS_PREC; |
191e56880 calibrate: home i... |
219 220 |
while (loopadd > chop_limit) { lpj += loopadd; |
71c696b1d calibrate: extrac... |
221 222 |
ticks = jiffies; while (ticks == jiffies) |
191e56880 calibrate: home i... |
223 |
; /* nothing */ |
71c696b1d calibrate: extrac... |
224 225 226 |
ticks = jiffies; __delay(lpj); if (jiffies != ticks) /* longer than 1 tick */ |
191e56880 calibrate: home i... |
227 228 |
lpj -= loopadd; loopadd >>= 1; |
71c696b1d calibrate: extrac... |
229 |
} |
b1b5f65e5 calibrate: retry ... |
230 231 232 233 234 235 236 237 238 239 |
/* * If we incremented every single time possible, presume we've * massively underestimated initially, and retry with a higher * start, and larger range. (Only seen on x86_64, due to SMIs) */ if (lpj + loopadd * 2 == lpj_base + loopadd_base * 2) { lpj_base = lpj; loopadd_base <<= 2; goto recalibrate; } |
71c696b1d calibrate: extrac... |
240 241 242 |
return lpj; } |
7afe1845d init: skip calibr... |
243 |
static DEFINE_PER_CPU(unsigned long, cpu_loops_per_jiffy) = { 0 }; |
71c696b1d calibrate: extrac... |
244 245 |
void __cpuinit calibrate_delay(void) { |
1b19ca9f0 Fix CPU spinlock ... |
246 |
unsigned long lpj; |
feae3203d timers, init: Lim... |
247 |
static bool printed; |
7afe1845d init: skip calibr... |
248 |
int this_cpu = smp_processor_id(); |
1da177e4c Linux-2.6.12-rc2 |
249 |
|
7afe1845d init: skip calibr... |
250 251 252 253 254 |
if (per_cpu(cpu_loops_per_jiffy, this_cpu)) { lpj = per_cpu(cpu_loops_per_jiffy, this_cpu); pr_info("Calibrating delay loop (skipped) " "already calibrated this CPU"); } else if (preset_lpj) { |
1b19ca9f0 Fix CPU spinlock ... |
255 |
lpj = preset_lpj; |
feae3203d timers, init: Lim... |
256 257 258 259 |
if (!printed) pr_info("Calibrating delay loop (skipped) " "preset value.. "); } else if ((!printed) && lpj_fine) { |
1b19ca9f0 Fix CPU spinlock ... |
260 |
lpj = lpj_fine; |
feae3203d timers, init: Lim... |
261 |
pr_info("Calibrating delay loop (skipped), " |
f3f3149f3 x86: use cpu_khz ... |
262 |
"value calculated using timer frequency.. "); |
1b19ca9f0 Fix CPU spinlock ... |
263 |
} else if ((lpj = calibrate_delay_direct()) != 0) { |
feae3203d timers, init: Lim... |
264 265 266 |
if (!printed) pr_info("Calibrating delay using timer " "specific routine.. "); |
1da177e4c Linux-2.6.12-rc2 |
267 |
} else { |
feae3203d timers, init: Lim... |
268 269 |
if (!printed) pr_info("Calibrating delay loop... "); |
1b19ca9f0 Fix CPU spinlock ... |
270 |
lpj = calibrate_delay_converge(); |
1da177e4c Linux-2.6.12-rc2 |
271 |
} |
7afe1845d init: skip calibr... |
272 |
per_cpu(cpu_loops_per_jiffy, this_cpu) = lpj; |
feae3203d timers, init: Lim... |
273 274 275 |
if (!printed) pr_cont("%lu.%02lu BogoMIPS (lpj=%lu) ", |
1b19ca9f0 Fix CPU spinlock ... |
276 277 |
lpj/(500000/HZ), (lpj/(5000/HZ)) % 100, lpj); |
feae3203d timers, init: Lim... |
278 |
|
1b19ca9f0 Fix CPU spinlock ... |
279 |
loops_per_jiffy = lpj; |
feae3203d timers, init: Lim... |
280 |
printed = true; |
1da177e4c Linux-2.6.12-rc2 |
281 |
} |