|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v2 1/4] x86/time: further improve TSC / CPU freq calibration accuracy
On 24.01.2022 09:25, Jan Beulich wrote:
> --- a/xen/arch/x86/time.c
> +++ b/xen/arch/x86/time.c
> @@ -287,9 +287,47 @@ static char *freq_string(u64 freq)
> return s;
> }
>
> -static uint64_t adjust_elapsed(uint64_t elapsed, uint32_t actual,
> - uint32_t target)
> +static uint32_t __init read_pt_and_tsc(uint64_t *tsc,
> + const struct platform_timesource *pts)
> {
> + uint64_t tsc_prev = *tsc = rdtsc_ordered(), tsc_min = ~0;
> + uint32_t best = best;
> + unsigned int i;
> +
> + for ( i = 0; ; ++i )
> + {
> + uint32_t pt = pts->read_counter();
> + uint64_t tsc_cur = rdtsc_ordered();
> + uint64_t tsc_delta = tsc_cur - tsc_prev;
> +
> + if ( tsc_delta < tsc_min )
> + {
> + tsc_min = tsc_delta;
> + *tsc = tsc_cur;
> + best = pt;
> + }
> + else if ( i > 2 )
> + break;
> +
> + tsc_prev = tsc_cur;
> + }
> +
> + return best;
> +}
> +
> +static uint64_t __init calibrate_tsc(const struct platform_timesource *pts)
> +{
> + uint64_t start, end, elapsed;
> + uint32_t count = read_pt_and_tsc(&start, pts);
> + uint32_t target = CALIBRATE_VALUE(pts->frequency), actual;
> + uint32_t mask = (uint32_t)~0 >> (32 - pts->counter_bits);
> +
> + while ( ((pts->read_counter() - count) & mask) < target )
> + continue;
> +
> + actual = read_pt_and_tsc(&end, pts) - count;
Having run into a case where the resulting CPU freq was 141 kHz (and
boot failing slightly later because of this), I've spotted that this
also needs masking by "mask", to guard against a 24-bit PM timer
wrapping between the earlier read and this one. The original code ...
> @@ -508,22 +539,12 @@ static u64 read_pmtimer_count(void)
>
> static s64 __init init_pmtimer(struct platform_timesource *pts)
> {
> - uint64_t start;
> - uint32_t count, target, mask, elapsed;
> -
> if ( !pmtmr_ioport || (pmtmr_width != 24 && pmtmr_width != 32) )
> return 0;
>
> pts->counter_bits = pmtmr_width;
> - mask = 0xffffffff >> (32 - pmtmr_width);
> -
> - count = inl(pmtmr_ioport);
> - start = rdtsc_ordered();
> - target = CALIBRATE_VALUE(ACPI_PM_FREQUENCY);
> - while ( (elapsed = (inl(pmtmr_ioport) - count) & mask) < target )
> - continue;
... ended up requiring use of "mask" just once.
Jan
> - return adjust_elapsed(rdtsc_ordered() - start, elapsed, target);
> + return calibrate_tsc(pts);
> }
>
> static struct platform_timesource __initdata plt_pmtimer =
>
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |