diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2008-09-03 10:30:13 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-09-03 10:30:13 -0400 |
| commit | ec0c15afb41fd9ad45b53468b60db50170e22346 (patch) | |
| tree | ba0b41ec5c1975949949ae7cb792bb1811aab97b | |
| parent | d26acd92fa990764b72608a68224f46fac377032 (diff) | |
Split up PIT part of TSC calibration from native_calibrate_tsc
The TSC calibration function is still very complicated, but this makes
it at least a little bit less so by moving the PIT part out into a
helper function of its own.
Tested-by: Larry Finger <Larry.Finger@lwfinger.net>
Signed-of-by: Linus Torvalds <torvalds@linux-foundation.org>
| -rw-r--r-- | arch/x86/kernel/tsc.c | 132 |
1 files changed, 71 insertions, 61 deletions
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index ac79bd143da8..346cae5ac423 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
| @@ -122,15 +122,75 @@ static u64 tsc_read_refs(u64 *pm, u64 *hpet) | |||
| 122 | return ULLONG_MAX; | 122 | return ULLONG_MAX; |
| 123 | } | 123 | } |
| 124 | 124 | ||
| 125 | /* | ||
| 126 | * Try to calibrate the TSC against the Programmable | ||
| 127 | * Interrupt Timer and return the frequency of the TSC | ||
| 128 | * in kHz. | ||
| 129 | * | ||
| 130 | * Return ULONG_MAX on failure to calibrate. | ||
| 131 | */ | ||
| 132 | static unsigned long pit_calibrate_tsc(void) | ||
| 133 | { | ||
| 134 | u64 tsc, t1, t2, delta; | ||
| 135 | unsigned long tscmin, tscmax; | ||
| 136 | int pitcnt; | ||
| 137 | |||
| 138 | /* Set the Gate high, disable speaker */ | ||
| 139 | outb((inb(0x61) & ~0x02) | 0x01, 0x61); | ||
| 140 | |||
| 141 | /* | ||
| 142 | * Setup CTC channel 2* for mode 0, (interrupt on terminal | ||
| 143 | * count mode), binary count. Set the latch register to 50ms | ||
| 144 | * (LSB then MSB) to begin countdown. | ||
| 145 | */ | ||
| 146 | outb(0xb0, 0x43); | ||
| 147 | outb((CLOCK_TICK_RATE / (1000 / 50)) & 0xff, 0x42); | ||
| 148 | outb((CLOCK_TICK_RATE / (1000 / 50)) >> 8, 0x42); | ||
| 149 | |||
| 150 | tsc = t1 = t2 = get_cycles(); | ||
| 151 | |||
| 152 | pitcnt = 0; | ||
| 153 | tscmax = 0; | ||
| 154 | tscmin = ULONG_MAX; | ||
| 155 | while ((inb(0x61) & 0x20) == 0) { | ||
| 156 | t2 = get_cycles(); | ||
| 157 | delta = t2 - tsc; | ||
| 158 | tsc = t2; | ||
| 159 | if ((unsigned long) delta < tscmin) | ||
| 160 | tscmin = (unsigned int) delta; | ||
| 161 | if ((unsigned long) delta > tscmax) | ||
| 162 | tscmax = (unsigned int) delta; | ||
| 163 | pitcnt++; | ||
| 164 | } | ||
| 165 | |||
| 166 | /* | ||
| 167 | * Sanity checks: | ||
| 168 | * | ||
| 169 | * If we were not able to read the PIT more than 5000 | ||
| 170 | * times, then we have been hit by a massive SMI | ||
| 171 | * | ||
| 172 | * If the maximum is 10 times larger than the minimum, | ||
| 173 | * then we got hit by an SMI as well. | ||
| 174 | */ | ||
| 175 | if (pitcnt < 5000 || tscmax > 10 * tscmin) | ||
| 176 | return ULONG_MAX; | ||
| 177 | |||
| 178 | /* Calculate the PIT value */ | ||
| 179 | delta = t2 - t1; | ||
| 180 | do_div(delta, 50); | ||
| 181 | return delta; | ||
| 182 | } | ||
| 183 | |||
| 184 | |||
| 125 | /** | 185 | /** |
| 126 | * native_calibrate_tsc - calibrate the tsc on boot | 186 | * native_calibrate_tsc - calibrate the tsc on boot |
| 127 | */ | 187 | */ |
| 128 | unsigned long native_calibrate_tsc(void) | 188 | unsigned long native_calibrate_tsc(void) |
| 129 | { | 189 | { |
| 130 | u64 tsc1, tsc2, tr1, tr2, tsc, delta, pm1, pm2, hpet1, hpet2; | 190 | u64 tsc1, tsc2, delta, pm1, pm2, hpet1, hpet2; |
| 131 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; | 191 | unsigned long tsc_pit_min = ULONG_MAX, tsc_ref_min = ULONG_MAX; |
| 132 | unsigned long flags, tscmin, tscmax; | 192 | unsigned long flags; |
| 133 | int hpet = is_hpet_enabled(), pitcnt, i; | 193 | int hpet = is_hpet_enabled(), i; |
| 134 | 194 | ||
| 135 | /* | 195 | /* |
| 136 | * Run 5 calibration loops to get the lowest frequency value | 196 | * Run 5 calibration loops to get the lowest frequency value |
| @@ -157,72 +217,22 @@ unsigned long native_calibrate_tsc(void) | |||
| 157 | * amount of time anyway. | 217 | * amount of time anyway. |
| 158 | */ | 218 | */ |
| 159 | for (i = 0; i < 5; i++) { | 219 | for (i = 0; i < 5; i++) { |
| 160 | 220 | unsigned long tsc_pit_khz; | |
| 161 | tscmin = ULONG_MAX; | ||
| 162 | tscmax = 0; | ||
| 163 | pitcnt = 0; | ||
| 164 | |||
| 165 | local_irq_save(flags); | ||
| 166 | 221 | ||
| 167 | /* | 222 | /* |
| 168 | * Read the start value and the reference count of | 223 | * Read the start value and the reference count of |
| 169 | * hpet/pmtimer when available: | 224 | * hpet/pmtimer when available. Then do the PIT |
| 225 | * calibration, which will take at least 50ms, and | ||
| 226 | * read the end value. | ||
| 170 | */ | 227 | */ |
| 228 | local_irq_save(flags); | ||
| 171 | tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); | 229 | tsc1 = tsc_read_refs(&pm1, hpet ? &hpet1 : NULL); |
| 172 | 230 | tsc_pit_khz = pit_calibrate_tsc(); | |
| 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); | 231 | tsc2 = tsc_read_refs(&pm2, hpet ? &hpet2 : NULL); |
| 205 | |||
| 206 | local_irq_restore(flags); | 232 | local_irq_restore(flags); |
| 207 | 233 | ||
| 208 | /* | 234 | /* Pick the lowest PIT TSC calibration so far */ |
| 209 | * Sanity checks: | 235 | tsc_pit_min = min(tsc_pit_min, tsc_pit_khz); |
| 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 | 236 | ||
| 227 | /* hpet or pmtimer available ? */ | 237 | /* hpet or pmtimer available ? */ |
| 228 | if (!hpet && !pm1 && !pm2) | 238 | if (!hpet && !pm1 && !pm2) |
