All of lore.kernel.org
 help / color / mirror / Atom feed
From: "Roger Pau Monné" <roger.pau@citrix.com>
To: Jan Beulich <jbeulich@suse.com>
Cc: "xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>,
	Andrew Cooper <andrew.cooper3@citrix.com>,
	Teddy Astie <teddy.astie@vates.tech>
Subject: Re: [PATCH v4 3/3] x86/time: avoid early uses of NOW() to return zero
Date: Tue, 28 Jul 2026 10:39:25 +0200	[thread overview]
Message-ID: <amhqvSAdzGjCuvCT@macbook.local> (raw)
In-Reply-To: <a53601c4-dab7-4d75-9cf0-323acc980ede@suse.com>

On Tue, Jun 30, 2026 at 04:06:41PM +0200, Jan Beulich wrote:
> Waiting loops like the one in flush_command_buffer() will degenerate to
> infinite ones when used early enough for NOW() to still return constant
> zero. Make sure the returned value at least monotonically increases. When
> available, use nominal frequency values as initial approximation.
> 
> Do this only in get_s_time(), as producing a sane value in
> get_s_time_fixed() for non-zero inputs won't be reasonably possible.
> Put an assertion there.
> 
> Reported-by: Roger Pau Monné <roger.pau@citrix.com>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
> ---
> RFC: While generally the mentioned waiting loops will take longer to time
>      out, on a very fast CPU tight loops may time out too early.

While we know this is not ideal, it's better than getting stuck in an
infinite NOW() loop without any timeout.  IMO it's best to timeout
early than not timeout at all.

> RFC: On the 2nd pass through early_cpu_init() it may be okay to skip the
>      new additions.

Possibly, yes, maybe add a static variable there to avoid re-doing?

> 
> With "x86/time: set AP's TSC scale estimate earlier" the counter update
> may not need to be atomic anymore, as then only the BSP can reasonably hit
> that path.
> 
> I don't think Fixes: tags should be put here. If we did, we'd have to
> enumerate all introductions of early uses of NOW() (or get_s_time()), with
> the exception of those dealing with getting back 0 (which I expect is only
> printk_start_of_line()). Will want backporting nevertheless (unless deemed
> too risky).
> ---
> v3: Use "high" / "max" freq if "nominal" isn't available. Set NOW_good.
> v2: Add assertion to get_s_time_fixed(). Use nominal frequencies for very
>     early setting, if available.
> 
> --- a/xen/arch/x86/cpu/common.c
> +++ b/xen/arch/x86/cpu/common.c
> @@ -19,6 +19,7 @@
>  #include <asm/random.h>
>  #include <asm/setup.h>
>  #include <asm/shstk.h>
> +#include <asm/time.h>
>  #include <asm/xstate.h>
>  
>  #include <public/sysctl.h>
> @@ -403,6 +404,36 @@ void __init early_cpu_init(bool verbose)
>  				    &c->x86_capability[FEATURESET_7d1]);
>  	}
>  
> +	if (c->cpuid_level >= 0x15) {
> +		cpuid(0x15, &eax, &ebx, &ecx, &edx);
> +
> +		if (ecx && ebx && eax)
> +			preset_tsc_scale(DIV_ROUND_UP(ecx * 1UL * ebx, eax));
> +		else if (c->cpuid_level >= 0x16) {
> +			/* Assume CPU base freq ≈ TSC freq. */
> +			cpuid(0x16, &eax, &ebx, &ecx, &edx);
> +			if (eax)
> +				preset_tsc_scale(eax * 1000000UL);
> +			else if (ebx) /* See preset_tsc_scale() for why. */
> +				preset_tsc_scale(ebx * 1000000UL);
> +		}
> +	} else if (c->vendor & (X86_VENDOR_AMD | X86_VENDOR_HYGON)) {
> +		unsigned int nom_mhz = 0, hi_mhz = 0;
> +
> +		amd_process_freq(c, NULL, &nom_mhz, &hi_mhz);
> +		if (nom_mhz)
> +			preset_tsc_scale(nom_mhz * 1000000UL);
> +		else if (hi_mhz) /* See preset_tsc_scale() for why. */
> +			preset_tsc_scale(hi_mhz * 1000000UL);
> +	} else if (c->vendor & X86_VENDOR_INTEL) {
> +		unsigned int hi_mhz = 0;
> +
> +		/* See preset_tsc_scale() for why. */

I would avoid those repeated "See preset_tsc_scale() for why."
comments, and simply state at the beginning of the block that either
the nominal or the higher reported frequencies will be used, as in the
worse case when using the high frequency the timer will run slower,
but not faster.

> +		intel_process_freq(c, NULL, &hi_mhz);
> +		if (hi_mhz)
> +			preset_tsc_scale(hi_mhz * 1000000UL);
> +	}
> +
>  	eax = cpuid_eax(0x80000000);
>  	if ((eax >> 16) == 0x8000 && eax >= 0x80000008) {
>  		ebx = eax >= 0x8000001f ? cpuid_ebx(0x8000001f) : 0;
> --- a/xen/arch/x86/include/asm/time.h
> +++ b/xen/arch/x86/include/asm/time.h
> @@ -23,6 +23,7 @@ mktime (unsigned int year, unsigned int
>  int time_suspend(void);
>  int time_resume(void);
>  
> +void preset_tsc_scale(unsigned long freq);
>  void init_percpu_time(void);
>  void time_latch_stamps(void);
>  
> --- a/xen/arch/x86/cpu/intel.c
> +++ b/xen/arch/x86/cpu/intel.c
> @@ -476,8 +476,8 @@ static int num_cpu_cores(struct cpuinfo_
>  		return 1;
>  }
>  
> -static void intel_process_freq(const struct cpuinfo_x86 *c,
> -                               unsigned int *min_mhz, unsigned int *max_mhz)
> +void intel_process_freq(const struct cpuinfo_x86 *c,
> +                        unsigned int *min_mhz, unsigned int *max_mhz)
>  {
>      uint64_t msrval;
>      uint8_t max_ratio, min_ratio;
> --- a/xen/arch/x86/include/asm/processor.h
> +++ b/xen/arch/x86/include/asm/processor.h
> @@ -417,6 +417,9 @@ static inline uint8_t get_cpu_family(uin
>      return fam;
>  }
>  
> +void intel_process_freq(const struct cpuinfo_x86 *c,
> +                        unsigned int *min_mhz, unsigned int *max_mhz);
> +
>  #ifdef CONFIG_INTEL
>  extern int8_t opt_tsx;
>  extern bool rtm_disabled;
> --- a/xen/arch/x86/time.c
> +++ b/xen/arch/x86/time.c
> @@ -1664,6 +1664,9 @@ s_time_t get_s_time_fixed(uint64_t at_ts
>      const struct cpu_time *t = &this_cpu(cpu_time);
>      uint64_t tsc, delta;
>  
> +    /* scale_delta() degenerates when the scale wasn't set yet. */
> +    ASSERT(t->tsc_scale.mul_frac);

Hm, so for release builds we would just return 0 in get_s_time_fixed()
when called before the scale is initialized.  I guess that's as good
as we can do.  I wonder whether using BUG_ON() won't be better here,
but it's likely best to return 0 than plain crash.

Thanks, Roger.


  reply	other threads:[~2026-07-28  8:39 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-06-30 14:04 [PATCH v4 0/3] x86/time: avoid early uses of NOW() to return zero Jan Beulich
2026-06-30 14:06 ` [PATCH v4 1/3] time: add "NOW() good" indicator Jan Beulich
2026-07-02  8:27   ` Oleksii Kurochko
2026-07-28  8:03   ` Roger Pau Monné
2026-07-28  8:17   ` Roger Pau Monné
2026-07-28  8:24     ` Jan Beulich
2026-07-28 10:32       ` Roger Pau Monné
2026-07-28 11:37         ` Jan Beulich
2026-06-30 14:06 ` [PATCH v4 2/3] x86/Intel: split model-specific freq calculation off of intel_log_freq() Jan Beulich
2026-07-28  8:16   ` Roger Pau Monné
2026-06-30 14:06 ` [PATCH v4 3/3] x86/time: avoid early uses of NOW() to return zero Jan Beulich
2026-07-28  8:39   ` Roger Pau Monné [this message]
2026-07-28  8:41   ` Roger Pau Monné
2026-07-28 10:01     ` Jan Beulich

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=amhqvSAdzGjCuvCT@macbook.local \
    --to=roger.pau@citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=jbeulich@suse.com \
    --cc=teddy.astie@vates.tech \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.