diff options
| -rw-r--r-- | arch/x86/kernel/tsc.c | 95 |
1 files changed, 58 insertions, 37 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 52284d31fc9c..da033b5b3e19 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -159,9 +159,14 @@ static unsigned long calc_pmtimer_ref(u64 deltatsc, u64 pm1, u64 pm2) | |||
| 159 | return (unsigned long) deltatsc; | 159 | return (unsigned long) deltatsc; |
| 160 | } | 160 | } |
| 161 | 161 | ||
| 162 | #define CAL_MS 50 | 162 | #define CAL_MS 10 |
| 163 | #define CAL_LATCH (CLOCK_TICK_RATE / (1000 / CAL_MS)) | 163 | #define CAL_LATCH (CLOCK_TICK_RATE / (1000 / CAL_MS)) |
| 164 | #define CAL_PIT_LOOPS 5000 | 164 | #define CAL_PIT_LOOPS 1000 |
| 165 | |||
| 166 | #define CAL2_MS 50 | ||
| 167 | #define CAL2_LATCH (CLOCK_TICK_RATE / (1000 / CAL2_MS)) | ||
| 168 | #define CAL2_PIT_LOOPS 5000 | ||
| 169 | |||
| 165 | 170 | ||
| 166 | /* | 171 | /* |
| 167 | * Try to calibrate the TSC against the Programmable | 172 | * Try to calibrate the TSC against the Programmable |
| @@ -170,7 +175,7 @@ static unsigned long calc_pmtimer_ref(u64 deltatsc, u64 pm1, u64 pm2) | |||
| 170 | * | 175 | * |
| 171 | * Return ULONG_MAX on failure to calibrate. | 176 | * Return ULONG_MAX on failure to calibrate. |
| 172 | */ | 177 | */ |
| 173 | static unsigned long pit_calibrate_tsc(void) | 178 | static unsigned long pit_calibrate_tsc(u32 latch, unsigned long ms, int loopmin) |
| 174 | { | 179 | { |
| 175 | u64 tsc, t1, t2, delta; | 180 | u64 tsc, t1, t2, delta; |
| 176 | unsigned long tscmin, tscmax; | 181 | unsigned long tscmin, tscmax; |
| @@ -185,8 +190,8 @@ static unsigned long pit_calibrate_tsc(void) | |||
| 185 | * (LSB then MSB) to begin countdown. | 190 | * (LSB then MSB) to begin countdown. |
| 186 | */ | 191 | */ |
| 187 | outb(0xb0, 0x43); | 192 | outb(0xb0, 0x43); |
| 188 | outb(CAL_LATCH & 0xff, 0x42); | 193 | outb(latch & 0xff, 0x42); |
| 189 | outb(CAL_LATCH >> 8, 0x42); | 194 | outb(latch >> 8, 0x42); |
| 190 | 195 | ||
| 191 | tsc = t1 = t2 = get_cycles(); | 196 | tsc = t1 = t2 = get_cycles(); |
| 192 | 197 | ||
| @@ -207,18 +212,18 @@ static unsigned long pit_calibrate_tsc(void) | |||
| 207 | /* | 212 | /* |
| 208 | * Sanity checks: | 213 | * Sanity checks: |
| 209 | * | 214 | * |
| 210 | * If we were not able to read the PIT more than PIT_MIN_LOOPS | 215 | * If we were not able to read the PIT more than loopmin |
| 211 | * times, then we have been hit by a massive SMI | 216 | * times, then we have been hit by a massive SMI |
| 212 | * | 217 | * |
| 213 | * If the maximum is 10 times larger than the minimum, | 218 | * If the maximum is 10 times larger than the minimum, |
| 214 | * then we got hit by an SMI as well. | 219 | * then we got hit by an SMI as well. |
| 215 | */ | 220 | */ |
| 216 | if (pitcnt < CAL_PIT_LOOPS || tscmax > 10 * tscmin) | 221 | if (pitcnt < loopmin || tscmax > 10 * tscmin) |
| 217 | return ULONG_MAX; | 222 | return ULONG_MAX; |
| 218 | 223 | ||
| 219 | /* Calculate the PIT value */ | 224 | /* Calculate the PIT value */ |
| 220 | delta = t2 - t1; | 225 | delta = t2 - t1; |
| 221 | do_div(delta, CAL_MS); | 226 | do_div(delta, ms); |
| 222 | return delta; | 227 | return delta; |
| 223 | } | 228 | } |
| 224 | 229 | ||
| @@ -230,8 +235,8 @@ unsigned long native_calibrate_tsc(void) | |||
| 230 | { | 235 | { |
| 231 | u64 tsc1, tsc2, delta, ref1, ref2; | 236 | u64 tsc1, tsc2, delta, ref1, ref2; |
| 232 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; | 237 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; |
| 233 | unsigned long flags; | 238 | unsigned long flags, latch, ms; |
| 234 | int hpet = is_hpet_enabled(), i; | 239 | int hpet = is_hpet_enabled(), i, loopmin; |
| 235 | 240 | ||
| 236 | /* | 241 | /* |
| 237 | * Run 5 calibration loops to get the lowest frequency value | 242 | * Run 5 calibration loops to get the lowest frequency value |
| @@ -257,7 +262,13 @@ unsigned long native_calibrate_tsc(void) | |||
| 257 | * calibration delay loop as we have to wait for a certain | 262 | * calibration delay loop as we have to wait for a certain |
| 258 | * amount of time anyway. | 263 | * amount of time anyway. |
| 259 | */ | 264 | */ |
| 260 | for (i = 0; i < 5; i++) { | 265 | |
| 266 | /* Preset PIT loop values */ | ||
| 267 | latch = CAL_LATCH; | ||
| 268 | ms = CAL_MS; | ||
| 269 | loopmin = CAL_PIT_LOOPS; | ||
| 270 | |||
| 271 | for (i = 0; i < 3; i++) { | ||
| 261 | unsigned long tsc_pit_khz; | 272 | unsigned long tsc_pit_khz; |
| 262 | 273 | ||
| 263 | /* | 274 | /* |
| @@ -268,7 +279,7 @@ unsigned long native_calibrate_tsc(void) | |||
| 268 | */ | 279 | */ |
| 269 | local_irq_save(flags); | 280 | local_irq_save(flags); |
| 270 | tsc1 = tsc_read_refs(&ref1, hpet); | 281 | tsc1 = tsc_read_refs(&ref1, hpet); |
| 271 | tsc_pit_khz = pit_calibrate_tsc(); | 282 | tsc_pit_khz = pit_calibrate_tsc(latch, ms, loopmin); |
| 272 | tsc2 = tsc_read_refs(&ref2, hpet); | 283 | tsc2 = tsc_read_refs(&ref2, hpet); |
| 273 | local_irq_restore(flags); | 284 | local_irq_restore(flags); |
| 274 | 285 | ||
| @@ -290,6 +301,35 @@ unsigned long native_calibrate_tsc(void) | |||
| 290 | tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2); | 301 | tsc2 = calc_pmtimer_ref(tsc2, ref1, ref2); |
| 291 | 302 | ||
| 292 | tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); | 303 | tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); |
| 304 | |||
| 305 | /* Check the reference deviation */ | ||
| 306 | delta = ((u64) tsc_pit_min) * 100; | ||
| 307 | do_div(delta, tsc_ref_min); | ||
| 308 | |||
| 309 | /* | ||
| 310 | * If both calibration results are inside a 10% window | ||
| 311 | * then we can be sure, that the calibration | ||
| 312 | * succeeded. We break out of the loop right away. We | ||
| 313 | * use the reference value, as it is more precise. | ||
| 314 | */ | ||
| 315 | if (delta >= 90 && delta <= 110) { | ||
| 316 | printk(KERN_INFO | ||
| 317 | "TSC: PIT calibration matches %s. %d loops\n", | ||
| 318 | hpet ? "HPET" : "PMTIMER", i + 1); | ||
| 319 | return tsc_ref_min; | ||
| 320 | } | ||
| 321 | |||
| 322 | /* | ||
| 323 | * Check whether PIT failed more than once. This | ||
| 324 | * happens in virtualized environments. We need to | ||
| 325 | * give the virtual PC a slightly longer timeframe for | ||
| 326 | * the HPET/PMTIMER to make the result precise. | ||
| 327 | */ | ||
| 328 | if (i == 1 && tsc_pit_min == ULONG_MAX) { | ||
| 329 | latch = CAL2_LATCH; | ||
| 330 | ms = CAL2_MS; | ||
| 331 | loopmin = CAL2_PIT_LOOPS; | ||
| 332 | } | ||
| 293 | } | 333 | } |
| 294 | 334 | ||
| 295 | /* | 335 | /* |
| @@ -309,7 +349,7 @@ unsigned long native_calibrate_tsc(void) | |||
| 309 | /* The alternative source failed as well, disable TSC */ | 349 | /* The alternative source failed as well, disable TSC */ |
| 310 | if (tsc_ref_min == ULONG_MAX) { | 350 | if (tsc_ref_min == ULONG_MAX) { |
| 311 | printk(KERN_WARNING "TSC: HPET/PMTIMER calibration " | 351 | printk(KERN_WARNING "TSC: HPET/PMTIMER calibration " |
| 312 | "failed due to SMI disturbance.\n"); | 352 | "failed.\n"); |
| 313 | return 0; | 353 | return 0; |
| 314 | } | 354 | } |
| 315 | 355 | ||
| @@ -328,37 +368,18 @@ unsigned long native_calibrate_tsc(void) | |||
| 328 | 368 | ||
| 329 | /* The alternative source failed, use the PIT calibration value */ | 369 | /* The alternative source failed, use the PIT calibration value */ |
| 330 | if (tsc_ref_min == ULONG_MAX) { | 370 | if (tsc_ref_min == ULONG_MAX) { |
| 331 | printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due " | 371 | printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed. " |
| 332 | "to SMI disturbance. Using PIT calibration\n"); | 372 | "Using PIT calibration\n"); |
| 333 | return tsc_pit_min; | 373 | return tsc_pit_min; |
| 334 | } | 374 | } |
| 335 | 375 | ||
| 336 | /* Check the reference deviation */ | ||
| 337 | delta = ((u64) tsc_pit_min) * 100; | ||
| 338 | do_div(delta, tsc_ref_min); | ||
| 339 | |||
| 340 | /* | ||
| 341 | * If both calibration results are inside a 5% window, the we | ||
| 342 | * use the lower frequency of those as it is probably the | ||
| 343 | * closest estimate. | ||
| 344 | */ | ||
| 345 | if (delta >= 95 && delta <= 105) { | ||
| 346 | printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n", | ||
| 347 | hpet ? "HPET" : "PMTIMER"); | ||
| 348 | printk(KERN_INFO "TSC: using %s calibration value\n", | ||
| 349 | tsc_pit_min <= tsc_ref_min ? "PIT" : | ||
| 350 | hpet ? "HPET" : "PMTIMER"); | ||
| 351 | return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min; | ||
| 352 | } | ||
| 353 | |||
| 354 | printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n", | ||
| 355 | hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min); | ||
| 356 | |||
| 357 | /* | 376 | /* |
| 358 | * The calibration values differ too much. In doubt, we use | 377 | * The calibration values differ too much. In doubt, we use |
| 359 | * the PIT value as we know that there are PMTIMERs around | 378 | * the PIT value as we know that there are PMTIMERs around |
| 360 | * running at double speed. | 379 | * running at double speed. At least we let the user know: |
| 361 | */ | 380 | */ |
| 381 | printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n", | ||
| 382 | hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min); | ||
| 362 | printk(KERN_INFO "TSC: Using PIT calibration value\n"); | 383 | printk(KERN_INFO "TSC: Using PIT calibration value\n"); |
| 363 | return tsc_pit_min; | 384 | return tsc_pit_min; |
| 364 | } | 385 | } |
