return s;
}
+static uint64_t adjust_elapsed(uint64_t elapsed, uint32_t actual,
+ uint32_t target)
+{
+ if ( likely(actual > target) )
+ {
+ /*
+ * A (perhaps significant) delay before the last timer read (e.g. due
+ * to a SMI or NMI) can lead to (perhaps severe) inaccuracy if not
+ * accounting for the time elapsed beyond the originally calculated
+ * duration of the calibration interval.
+ */
+ elapsed = muldiv64(elapsed, target, actual);
+ }
+
+ return elapsed * CALIBRATE_FRAC;
+}
+
/************************************************************
* PLATFORM TIMER 1: PROGRAMMABLE INTERVAL TIMER (LEGACY PIT)
*/
while ( (elapsed = hpet_read32(HPET_COUNTER) - count) < target )
continue;
- return (rdtsc_ordered() - start) * CALIBRATE_FRAC;
+ return adjust_elapsed(rdtsc_ordered() - start, elapsed, target);
}
static void resume_hpet(struct platform_timesource *pts)
while ( (elapsed = (inl(pmtmr_ioport) - count) & mask) < target )
continue;
- return (rdtsc_ordered() - start) * CALIBRATE_FRAC;
+ return adjust_elapsed(rdtsc_ordered() - start, elapsed, target);
}
static struct platform_timesource __initdata plt_pmtimer =