diff options
| -rw-r--r-- | arch/x86/kernel/tsc.c | 235 |
1 files changed, 181 insertions, 54 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 8e786b0d665a..ac79bd143da8 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -127,75 +127,202 @@ static u64 tsc_read_refs(u64 *pm, u64 *hpet) | |||
| 127 | */ | 127 | */ |
| 128 | unsigned long native_calibrate_tsc(void) | 128 | unsigned long native_calibrate_tsc(void) |
| 129 | { | 129 | { |
| 130 | unsigned long flags; | 130 | u64 tsc1, tsc2, tr1, tr2, tsc, delta, pm1, pm2, hpet1, hpet2; |
| 131 | u64 tsc1, tsc2, tr1, tr2, delta, pm1, pm2, hpet1, hpet2; | 131 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; |
| 132 | int hpet = is_hpet_enabled(); | 132 | unsigned long flags, tscmin, tscmax; |
| 133 | unsigned int tsc_khz_val = 0; | 133 | int hpet = is_hpet_enabled(), pitcnt, i; |
| 134 | 134 | ||
| 135 | local_irq_save(flags); | 135 | /* |
| 136 | 136 | * Run 5 calibration loops to get the lowest frequency value | |
| 137 | tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); | 137 | * (the best estimate). We use two different calibration modes |
| 138 | 138 | * here: | |
| 139 | outb((inb(0x61) & ~0x02) | 0x01, 0x61); | 139 | * |
| 140 | 140 | * 1) PIT loop. We set the PIT Channel 2 to oneshot mode and | |
| 141 | outb(0xb0, 0x43); | 141 | * load a timeout of 50ms. We read the time right after we |
| 142 | outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); | 142 | * started the timer and wait until the PIT count down reaches |
| 143 | outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); | 143 | * zero. In each wait loop iteration we read the TSC and check |
| 144 | tr1 = get_cycles(); | 144 | * the delta to the previous read. We keep track of the min |
| 145 | while ((inb(0x61) & 0x20) == 0); | 145 | * and max values of that delta. The delta is mostly defined |
| 146 | tr2 = get_cycles(); | 146 | * by the IO time of the PIT access, so we can detect when a |
| 147 | 147 | * SMI/SMM disturbance happend between the two reads. If the | |
| 148 | tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); | 148 | * maximum time is significantly larger than the minimum time, |
| 149 | 149 | * then we discard the result and have another try. | |
| 150 | local_irq_restore(flags); | 150 | * |
| 151 | * 2) Reference counter. If available we use the HPET or the | ||
| 152 | * PMTIMER as a reference to check the sanity of that value. | ||
| 153 | * We use separate TSC readouts and check inside of the | ||
| 154 | * reference read for a SMI/SMM disturbance. We dicard | ||
| 155 | * disturbed values here as well. We do that around the PIT | ||
| 156 | * calibration delay loop as we have to wait for a certain | ||
| 157 | * amount of time anyway. | ||
| 158 | */ | ||
| 159 | for (i = 0; i < 5; i++) { | ||
| 160 | |||
| 161 | tscmin = ULONG_MAX; | ||
| 162 | tscmax = 0; | ||
| 163 | pitcnt = 0; | ||
| 164 | |||
| 165 | local_irq_save(flags); | ||
| 166 | |||
| 167 | /* | ||
| 168 | * Read the start value and the reference count of | ||
| 169 | * hpet/pmtimer when available: | ||
| 170 | */ | ||
| 171 | tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); | ||
| 172 | |||
| 173 | /* Set the Gate high, disable speaker */ | ||
| 174 | outb((inb(0x61) & ~0x02) | 0x01, 0x61); | ||
| 175 | |||
| 176 | /* | ||
| 177 | * Setup CTC channel 2* for mode 0, (interrupt on terminal | ||
| 178 | * count mode), binary count. Set the latch register to 50ms | ||
| 179 | * (LSB then MSB) to begin countdown. | ||
| 180 | * | ||
| 181 | * Some devices need a delay here. | ||
| 182 | */ | ||
| 183 | outb(0xb0, 0x43); | ||
| 184 | outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); | ||
| 185 | outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); | ||
| 186 | |||
| 187 | tsc = tr1 = tr2 = get_cycles(); | ||
| 188 | |||
| 189 | while ((inb(0x61) & 0x20) == 0) { | ||
| 190 | tr2 = get_cycles(); | ||
| 191 | delta = tr2 - tsc; | ||
| 192 | tsc = tr2; | ||
| 193 | if ((unsigned int) delta < tscmin) | ||
| 194 | tscmin = (unsigned int) delta; | ||
| 195 | if ((unsigned int) delta > tscmax) | ||
| 196 | tscmax = (unsigned int) delta; | ||
| 197 | pitcnt++; | ||
| 198 | } | ||
| 199 | |||
| 200 | /* | ||
| 201 | * We waited at least 50ms above. Now read | ||
| 202 | * pmtimer/hpet reference again | ||
| 203 | */ | ||
| 204 | tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); | ||
| 205 | |||
| 206 | local_irq_restore(flags); | ||
| 207 | |||
| 208 | /* | ||
| 209 | * Sanity checks: | ||
| 210 | * | ||
| 211 | * If we were not able to read the PIT more than 5000 | ||
| 212 | * times, then we have been hit by a massive SMI | ||
| 213 | * | ||
| 214 | * If the maximum is 10 times larger than the minimum, | ||
| 215 | * then we got hit by an SMI as well. | ||
| 216 | */ | ||
| 217 | if (pitcnt > 5000 && tscmax < 10 * tscmin) { | ||
| 218 | |||
| 219 | /* Calculate the PIT value */ | ||
| 220 | delta = tr2 - tr1; | ||
| 221 | do_div(delta, 50); | ||
| 222 | |||
| 223 | /* We take the smallest value into account */ | ||
| 224 | tsc_pit_min = min(tsc_pit_min, (unsigned long) delta); | ||
| 225 | } | ||
| 226 | |||
| 227 | /* hpet or pmtimer available ? */ | ||
| 228 | if (!hpet && !pm1 && !pm2) | ||
| 229 | continue; | ||
| 230 | |||
| 231 | /* Check, whether the sampling was disturbed by an SMI */ | ||
| 232 | if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) | ||
| 233 | continue; | ||
| 234 | |||
| 235 | tsc2 = (tsc2 - tsc1) * 1000000LL; | ||
| 236 | |||
| 237 | if (hpet) { | ||
| 238 | if (hpet2 < hpet1) | ||
| 239 | hpet2 += 0x100000000ULL; | ||
| 240 | hpet2 -= hpet1; | ||
| 241 | tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); | ||
| 242 | do_div(tsc1, 1000000); | ||
| 243 | } else { | ||
| 244 | if (pm2 < pm1) | ||
| 245 | pm2 += (u64)ACPI_PM_OVRRUN; | ||
| 246 | pm2 -= pm1; | ||
| 247 | tsc1 = pm2 * 1000000000LL; | ||
| 248 | do_div(tsc1, PMTMR_TICKS_PER_SEC); | ||
| 249 | } | ||
| 250 | |||
| 251 | do_div(tsc2, tsc1); | ||
| 252 | tsc_ref_min = min(tsc_ref_min, (unsigned long) tsc2); | ||
| 253 | } | ||
| 151 | 254 | ||
| 152 | /* | 255 | /* |
| 153 | * Preset the result with the raw and inaccurate PIT | 256 | * Now check the results. |
| 154 | * calibration value | ||
| 155 | */ | 257 | */ |
| 156 | delta = (tr2 - tr1); | 258 | if (tsc_pit_min == ULONG_MAX) { |
| 157 | do_div(delta, 50); | 259 | /* PIT gave no useful value */ |
| 158 | tsc_khz_val = delta; | 260 | printk(KERN_WARNING "TSC: PIT calibration failed due to " |
| 261 | "SMI disturbance.\n"); | ||
| 262 | |||
| 263 | /* We don't have an alternative source, disable TSC */ | ||
| 264 | if (!hpet && !pm1 && !pm2) { | ||
| 265 | printk("TSC: No reference (HPET/PMTIMER) available\n"); | ||
| 266 | return 0; | ||
| 267 | } | ||
| 268 | |||
| 269 | /* The alternative source failed as well, disable TSC */ | ||
| 270 | if (tsc_ref_min == ULONG_MAX) { | ||
| 271 | printk(KERN_WARNING "TSC: HPET/PMTIMER calibration " | ||
| 272 | "failed due to SMI disturbance.\n"); | ||
| 273 | return 0; | ||
| 274 | } | ||
| 275 | |||
| 276 | /* Use the alternative source */ | ||
| 277 | printk(KERN_INFO "TSC: using %s reference calibration\n", | ||
| 278 | hpet ? "HPET" : "PMTIMER"); | ||
| 279 | |||
| 280 | return tsc_ref_min; | ||
| 281 | } | ||
| 159 | 282 | ||
| 160 | /* hpet or pmtimer available ? */ | 283 | /* We don't have an alternative source, use the PIT calibration value */ |
| 161 | if (!hpet && !pm1 && !pm2) { | 284 | if (!hpet && !pm1 && !pm2) { |
| 162 | printk(KERN_INFO "TSC calibrated against PIT\n"); | 285 | printk(KERN_INFO "TSC: Using PIT calibration value\n"); |
| 163 | goto out; | 286 | return tsc_pit_min; |
| 164 | } | 287 | } |
| 165 | 288 | ||
| 166 | /* Check, whether the sampling was disturbed by an SMI */ | 289 | /* The alternative source failed, use the PIT calibration value */ |
| 167 | if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) { | 290 | if (tsc_ref_min == ULONG_MAX) { |
| 168 | printk(KERN_WARNING "TSC calibration disturbed by SMI, " | 291 | printk(KERN_WARNING "TSC: HPET/PMTIMER calibration failed due " |
| 169 | "using PIT calibration result\n"); | 292 | "to SMI disturbance. Using PIT calibration\n"); |
| 170 | goto out; | 293 | return tsc_pit_min; |
| 171 | } | 294 | } |
| 172 | 295 | ||
| 173 | tsc2 = (tsc2 - tsc1) * 1000000LL; | 296 | /* Check the reference deviation */ |
| 174 | 297 | delta = ((u64) tsc_pit_min) * 100; | |
| 175 | if (hpet) { | 298 | do_div(delta, tsc_ref_min); |
| 176 | printk(KERN_INFO "TSC calibrated against HPET\n"); | 299 | |
| 177 | if (hpet2 < hpet1) | 300 | /* |
| 178 | hpet2 += 0x100000000ULL; | 301 | * If both calibration results are inside a 5% window, the we |
| 179 | hpet2 -= hpet1; | 302 | * use the lower frequency of those as it is probably the |
| 180 | tsc1 = ((u64)hpet2 * hpet_readl(HPET_PERIOD)); | 303 | * closest estimate. |
| 181 | do_div(tsc1, 1000000); | 304 | */ |
| 182 | } else { | 305 | if (delta >= 95 && delta <= 105) { |
| 183 | printk(KERN_INFO "TSC calibrated against PM_TIMER\n"); | 306 | printk(KERN_INFO "TSC: PIT calibration confirmed by %s.\n", |
| 184 | if (pm2 < pm1) | 307 | hpet ? "HPET" : "PMTIMER"); |
| 185 | pm2 += (u64)ACPI_PM_OVRRUN; | 308 | printk(KERN_INFO "TSC: using %s calibration value\n", |
| 186 | pm2 -= pm1; | 309 | tsc_pit_min <= tsc_ref_min ? "PIT" : |
| 187 | tsc1 = pm2 * 1000000000LL; | 310 | hpet ? "HPET" : "PMTIMER"); |
| 188 | do_div(tsc1, PMTMR_TICKS_PER_SEC); | 311 | return tsc_pit_min <= tsc_ref_min ? tsc_pit_min : tsc_ref_min; |
| 189 | } | 312 | } |
| 190 | 313 | ||
| 191 | do_div(tsc2, tsc1); | 314 | printk(KERN_WARNING "TSC: PIT calibration deviates from %s: %lu %lu.\n", |
| 192 | tsc_khz_val = tsc2; | 315 | hpet ? "HPET" : "PMTIMER", tsc_pit_min, tsc_ref_min); |
| 193 | 316 | ||
| 194 | out: | 317 | /* |
| 195 | return tsc_khz_val; | 318 | * The calibration values differ too much. In doubt, we use |
| 319 | * the PIT value as we know that there are PMTIMERs around | ||
| 320 | * running at double speed. | ||
| 321 | */ | ||
| 322 | printk(KERN_INFO "TSC: Using PIT calibration value\n"); | ||
| 323 | return tsc_pit_min; | ||
| 196 | } | 324 | } |
| 197 | 325 | ||
| 198 | |||
| 199 | #ifdef CONFIG_X86_32 | 326 | #ifdef CONFIG_X86_32 |
| 200 | /* Only called from the Powernow K7 cpu freq driver */ | 327 | /* Only called from the Powernow K7 cpu freq driver */ |
| 201 | int recalibrate_cpu_khz(void) | 328 | int recalibrate_cpu_khz(void) |
