All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 0/6] x86/time: improvements to wallclock logic
@ 2024-09-04 15:31 Roger Pau Monne
  2024-09-04 15:31 ` [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest Roger Pau Monne
                   ` (5 more replies)
  0 siblings, 6 replies; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Jan Beulich, Andrew Cooper, Julien Grall, Stefano Stabellini

Hello,

This series started as an attempt to change the default wallclock
preference from EFI_GET_TIME to CMOS RTC, but has grown quite a lot.
First 3 patches should be non-functional changes, mostly chopping the
current logic into smaller functions so that in patch 4 the probing vs
runtime wallclock logic can be split. Patch 5 adds a new command line
option to force the usage of a specific wallclock.

Finally patch 6 changes the preference to use CMOS RTC even when booted
from EFI firmware.

Thanks, Roger.

Roger Pau Monne (6):
  x86/time: introduce helper to fetch Xen wallclock when running as a
    guest
  x86/time: move CMOS edge detection into read helper
  x86/time: split CMOS read and probe logic into function
  x86/time: introduce probing logic for the wallclock
  x86/time: introduce command line option to select wallclock
  x86/time: prefer CMOS over EFI_GET_TIME

 docs/misc/xen-command-line.pandoc |  19 +++
 xen/arch/x86/time.c               | 236 ++++++++++++++++++++++--------
 2 files changed, 198 insertions(+), 57 deletions(-)

-- 
2.46.0



^ permalink raw reply	[flat|nested] 13+ messages in thread

* [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest
  2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
@ 2024-09-04 15:31 ` Roger Pau Monne
  2024-09-05 15:45   ` Jan Beulich
  2024-09-04 15:31 ` [PATCH v4 2/6] x86/time: move CMOS edge detection into read helper Roger Pau Monne
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Jan Beulich, Andrew Cooper

Move the current code in get_wallclock_time() to fetch the Xen wallclock
information from the shared page when running as a guest into a separate
helper.

No functional change intended.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v3:
 - Place ifdef blocks inside the function.

Changes since v2:
 - New in this version.
---
 xen/arch/x86/time.c | 42 +++++++++++++++++++++++++-----------------
 1 file changed, 25 insertions(+), 17 deletions(-)

diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index a97d78484105..1959cc4a4f2b 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -787,6 +787,30 @@ static struct platform_timesource __initdata_cf_clobber plt_xen_timer =
 };
 #endif
 
+static unsigned long read_xen_wallclock(void)
+{
+#ifdef CONFIG_XEN_GUEST
+    struct shared_info *sh_info = XEN_shared_info;
+    uint32_t wc_version;
+    uint64_t wc_sec;
+
+    ASSERT(xen_guest);
+
+    do {
+        wc_version = sh_info->wc_version & ~1;
+        smp_rmb();
+
+        wc_sec  = sh_info->wc_sec;
+        smp_rmb();
+    } while ( wc_version != sh_info->wc_version );
+
+    return wc_sec + read_xen_timer() / 1000000000;
+#else
+    ASSERT_UNREACHABLE();
+    return 0;
+#endif
+}
+
 #ifdef CONFIG_HYPERV_GUEST
 /************************************************************
  * HYPER-V REFERENCE TSC
@@ -1497,24 +1521,8 @@ void rtc_guest_write(unsigned int port, unsigned int data)
 
 static unsigned long get_wallclock_time(void)
 {
-#ifdef CONFIG_XEN_GUEST
     if ( xen_guest )
-    {
-        struct shared_info *sh_info = XEN_shared_info;
-        uint32_t wc_version;
-        uint64_t wc_sec;
-
-        do {
-            wc_version = sh_info->wc_version & ~1;
-            smp_rmb();
-
-            wc_sec  = sh_info->wc_sec;
-            smp_rmb();
-        } while ( wc_version != sh_info->wc_version );
-
-        return wc_sec + read_xen_timer() / 1000000000;
-    }
-#endif
+        return read_xen_wallclock();
 
     return get_cmos_time();
 }
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 2/6] x86/time: move CMOS edge detection into read helper
  2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
  2024-09-04 15:31 ` [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest Roger Pau Monne
@ 2024-09-04 15:31 ` Roger Pau Monne
  2024-09-05 15:46   ` Jan Beulich
  2024-09-04 15:31 ` [PATCH v4 3/6] x86/time: split CMOS read and probe logic into function Roger Pau Monne
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Jan Beulich, Andrew Cooper

Move the logic that ensures the CMOS RTC data is read just after it's been
updated into the __get_cmos_time() function that does the register reads.  This
requires returning a boolean from __get_cmos_time() to signal whether the read
has been successfully performed after an update.

Note that while __get_cmos_time() can be used without waiting for the update
edge, so far the only caller does wait for it, hence move the code inside of
the function.

The goal, albeit not accomplished by this patch, is to be able to split the
probing and the reading of the CMOS RTC data into two separate functions.

No functional change intended.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v3:
 - Reduce a bit the locked section.

Changes since v2:
 - New in this version.
---
 xen/arch/x86/time.c | 50 +++++++++++++++++++++++----------------------
 1 file changed, 26 insertions(+), 24 deletions(-)

diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 1959cc4a4f2b..571e23431ccd 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -1246,8 +1246,26 @@ struct rtc_time {
     unsigned int year, mon, day, hour, min, sec;
 };
 
-static void __get_cmos_time(struct rtc_time *rtc)
+static bool __get_cmos_time(struct rtc_time *rtc)
 {
+    s_time_t start, t1, t2;
+    unsigned long flags;
+
+    spin_lock_irqsave(&rtc_lock, flags);
+
+    /* read RTC exactly on falling edge of update flag */
+    start = NOW();
+    do { /* may take up to 1 second... */
+        t1 = NOW() - start;
+    } while ( !(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) &&
+              t1 <= SECONDS(1) );
+
+    start = NOW();
+    do { /* must try at least 2.228 ms */
+        t2 = NOW() - start;
+    } while ( (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) &&
+              t2 < MILLISECS(3) );
+
     rtc->sec  = CMOS_READ(RTC_SECONDS);
     rtc->min  = CMOS_READ(RTC_MINUTES);
     rtc->hour = CMOS_READ(RTC_HOURS);
@@ -1265,13 +1283,17 @@ static void __get_cmos_time(struct rtc_time *rtc)
         BCD_TO_BIN(rtc->year);
     }
 
+    spin_unlock_irqrestore(&rtc_lock, flags);
+
     if ( (rtc->year += 1900) < 1970 )
         rtc->year += 100;
+
+    return t1 <= SECONDS(1) && t2 < MILLISECS(3);
 }
 
 static unsigned long get_cmos_time(void)
 {
-    unsigned long res, flags;
+    unsigned long res;
     struct rtc_time rtc;
     unsigned int seconds = 60;
     static bool __read_mostly cmos_rtc_probe;
@@ -1292,29 +1314,9 @@ static unsigned long get_cmos_time(void)
 
     for ( ; ; )
     {
-        s_time_t start, t1, t2;
-
-        spin_lock_irqsave(&rtc_lock, flags);
-
-        /* read RTC exactly on falling edge of update flag */
-        start = NOW();
-        do { /* may take up to 1 second... */
-            t1 = NOW() - start;
-        } while ( !(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) &&
-                  t1 <= SECONDS(1) );
-
-        start = NOW();
-        do { /* must try at least 2.228 ms */
-            t2 = NOW() - start;
-        } while ( (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) &&
-                  t2 < MILLISECS(3) );
-
-        __get_cmos_time(&rtc);
-
-        spin_unlock_irqrestore(&rtc_lock, flags);
+        bool success = __get_cmos_time(&rtc);
 
-        if ( likely(!cmos_rtc_probe) ||
-             t1 > SECONDS(1) || t2 >= MILLISECS(3) ||
+        if ( likely(!cmos_rtc_probe) || !success ||
              rtc.sec >= 60 || rtc.min >= 60 || rtc.hour >= 24 ||
              !rtc.day || rtc.day > 31 ||
              !rtc.mon || rtc.mon > 12 )
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 3/6] x86/time: split CMOS read and probe logic into function
  2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
  2024-09-04 15:31 ` [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest Roger Pau Monne
  2024-09-04 15:31 ` [PATCH v4 2/6] x86/time: move CMOS edge detection into read helper Roger Pau Monne
@ 2024-09-04 15:31 ` Roger Pau Monne
  2024-09-05 15:49   ` Jan Beulich
  2024-09-04 15:31 ` [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock Roger Pau Monne
                   ` (2 subsequent siblings)
  5 siblings, 1 reply; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Jan Beulich, Andrew Cooper

The current logic to probe for the CMOS RTC is open-coded in get_cmos_time(),
move it to a separate function that both serves the purpose of testing for the
CMOS RTC existence and returning its value.

The goal is to be able to split the probing and the reading logic into separate
helpers, and putting the current logic in a separate function helps simplifying
further changes.

A transient *rtc_p variable is introduced as a parameter to the function, that
will be removed by further changes.  Also note that due to the code movement,
now cmos_rtc_probe will only get cleared on a second call to get_cmos_time(),
as the newly introduced cmos_probe() function doesn't modify the variable
anymore.

No functional change intended.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v2:
 - New in this version.
---
 xen/arch/x86/time.c | 59 +++++++++++++++++++++++++++------------------
 1 file changed, 35 insertions(+), 24 deletions(-)

diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 571e23431ccd..1e3c13fc7360 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -1291,45 +1291,32 @@ static bool __get_cmos_time(struct rtc_time *rtc)
     return t1 <= SECONDS(1) && t2 < MILLISECS(3);
 }
 
-static unsigned long get_cmos_time(void)
+static bool cmos_probe(struct rtc_time *rtc_p, bool cmos_rtc_probe)
 {
-    unsigned long res;
-    struct rtc_time rtc;
     unsigned int seconds = 60;
-    static bool __read_mostly cmos_rtc_probe;
-    boolean_param("cmos-rtc-probe", cmos_rtc_probe);
-
-    if ( efi_enabled(EFI_RS) )
-    {
-        res = efi_get_time();
-        if ( res )
-            return res;
-    }
-
-    if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) )
-        cmos_rtc_probe = false;
-    else if ( system_state < SYS_STATE_smp_boot && !cmos_rtc_probe )
-        panic("System with no CMOS RTC advertised must be booted from EFI"
-              " (or with command line option \"cmos-rtc-probe\")\n");
 
     for ( ; ; )
     {
-        bool success = __get_cmos_time(&rtc);
+        bool success = __get_cmos_time(rtc_p);
+        struct rtc_time rtc = *rtc_p;
 
-        if ( likely(!cmos_rtc_probe) || !success ||
+        if ( likely(!cmos_rtc_probe) )
+            return true;
+
+        if ( !success ||
              rtc.sec >= 60 || rtc.min >= 60 || rtc.hour >= 24 ||
              !rtc.day || rtc.day > 31 ||
              !rtc.mon || rtc.mon > 12 )
-            break;
+            return false;
 
         if ( seconds < 60 )
         {
             if ( rtc.sec != seconds )
             {
-                cmos_rtc_probe = false;
                 acpi_gbl_FADT.boot_flags &= ~ACPI_FADT_NO_CMOS_RTC;
+                return true;
             }
-            break;
+            return false;
         }
 
         process_pending_softirqs();
@@ -1337,7 +1324,31 @@ static unsigned long get_cmos_time(void)
         seconds = rtc.sec;
     }
 
-    if ( unlikely(cmos_rtc_probe) )
+    ASSERT_UNREACHABLE();
+    return false;
+}
+
+static unsigned long get_cmos_time(void)
+{
+    unsigned long res;
+    struct rtc_time rtc;
+    static bool __read_mostly cmos_rtc_probe;
+    boolean_param("cmos-rtc-probe", cmos_rtc_probe);
+
+    if ( efi_enabled(EFI_RS) )
+    {
+        res = efi_get_time();
+        if ( res )
+            return res;
+    }
+
+    if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) )
+        cmos_rtc_probe = false;
+    else if ( system_state < SYS_STATE_smp_boot && !cmos_rtc_probe )
+        panic("System with no CMOS RTC advertised must be booted from EFI"
+              " (or with command line option \"cmos-rtc-probe\")\n");
+
+    if ( !cmos_probe(&rtc, cmos_rtc_probe) )
         panic("No CMOS RTC found - system must be booted from EFI\n");
 
     return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec);
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock
  2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
                   ` (2 preceding siblings ...)
  2024-09-04 15:31 ` [PATCH v4 3/6] x86/time: split CMOS read and probe logic into function Roger Pau Monne
@ 2024-09-04 15:31 ` Roger Pau Monne
  2024-09-05 15:58   ` Jan Beulich
  2024-09-04 15:31 ` [PATCH v4 5/6] x86/time: introduce command line option to select wallclock Roger Pau Monne
  2024-09-04 15:31 ` [PATCH v4 6/6] x86/time: prefer CMOS over EFI_GET_TIME Roger Pau Monne
  5 siblings, 1 reply; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Jan Beulich, Andrew Cooper

Adding such probing allows to clearly separate init vs runtime code, and to
place the probing logic into the init section for the CMOS case.  Note both
the Xen shared_info page wallclock, and the EFI wallclock don't really have any
probing-specific logic.  The shared_info wallclock will always be there if
booted as a Xen guest, while the EFI_GET_TIME method probing relies on checking
if it returns a value different than 0.

The panic message printed when Xen is unable to find a viable wallclock source
has been adjusted slightly, I believe the printed guidance still provides the
same amount of information to the user.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v3:
 - Remove ASSERT from cmos_read().
 - Change indentation of panic message arguments in probe_wallclock().
 - Add __init attribute.

Changes since v2:
 - New in this version.
---
 xen/arch/x86/time.c | 118 +++++++++++++++++++++++++++++++++++---------
 1 file changed, 94 insertions(+), 24 deletions(-)

diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 1e3c13fc7360..9ebeee61b987 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -1291,14 +1291,23 @@ static bool __get_cmos_time(struct rtc_time *rtc)
     return t1 <= SECONDS(1) && t2 < MILLISECS(3);
 }
 
-static bool cmos_probe(struct rtc_time *rtc_p, bool cmos_rtc_probe)
+static bool __initdata cmos_rtc_probe;
+boolean_param("cmos-rtc-probe", cmos_rtc_probe);
+
+static bool __init cmos_probe(void)
 {
     unsigned int seconds = 60;
 
+    if ( !(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) )
+        return true;
+
+    if ( !cmos_rtc_probe )
+        return false;
+
     for ( ; ; )
     {
-        bool success = __get_cmos_time(rtc_p);
-        struct rtc_time rtc = *rtc_p;
+        struct rtc_time rtc;
+        bool success = __get_cmos_time(&rtc);
 
         if ( likely(!cmos_rtc_probe) )
             return true;
@@ -1328,28 +1337,12 @@ static bool cmos_probe(struct rtc_time *rtc_p, bool cmos_rtc_probe)
     return false;
 }
 
-static unsigned long get_cmos_time(void)
+
+static unsigned long cmos_read(void)
 {
-    unsigned long res;
     struct rtc_time rtc;
-    static bool __read_mostly cmos_rtc_probe;
-    boolean_param("cmos-rtc-probe", cmos_rtc_probe);
 
-    if ( efi_enabled(EFI_RS) )
-    {
-        res = efi_get_time();
-        if ( res )
-            return res;
-    }
-
-    if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) )
-        cmos_rtc_probe = false;
-    else if ( system_state < SYS_STATE_smp_boot && !cmos_rtc_probe )
-        panic("System with no CMOS RTC advertised must be booted from EFI"
-              " (or with command line option \"cmos-rtc-probe\")\n");
-
-    if ( !cmos_probe(&rtc, cmos_rtc_probe) )
-        panic("No CMOS RTC found - system must be booted from EFI\n");
+    __get_cmos_time(&rtc);
 
     return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec);
 }
@@ -1532,12 +1525,85 @@ void rtc_guest_write(unsigned int port, unsigned int data)
     }
 }
 
-static unsigned long get_wallclock_time(void)
+static enum {
+    WALLCLOCK_UNSET,
+    WALLCLOCK_XEN,
+    WALLCLOCK_CMOS,
+    WALLCLOCK_EFI,
+} wallclock_source __ro_after_init;
+
+static const char *__init wallclock_type_to_string(void)
 {
+    switch ( wallclock_source )
+    {
+    case WALLCLOCK_XEN:
+        return "XEN";
+
+    case WALLCLOCK_CMOS:
+        return "CMOS RTC";
+
+    case WALLCLOCK_EFI:
+        return "EFI";
+
+    case WALLCLOCK_UNSET:
+        return "UNSET";
+    }
+
+    ASSERT_UNREACHABLE();
+    return "";
+}
+
+static void __init probe_wallclock(void)
+{
+    ASSERT(wallclock_source == WALLCLOCK_UNSET);
+
     if ( xen_guest )
+    {
+        wallclock_source = WALLCLOCK_XEN;
+        return;
+    }
+    if ( efi_enabled(EFI_RS) && efi_get_time() )
+    {
+        wallclock_source = WALLCLOCK_EFI;
+        return;
+    }
+    if ( cmos_probe() )
+    {
+        wallclock_source = WALLCLOCK_CMOS;
+        return;
+    }
+
+    panic("No usable wallclock found, probed:%s%s%s\n%s",
+          !cmos_rtc_probe && !efi_enabled(EFI_RS) ? " None" : "",
+          cmos_rtc_probe ? " CMOS" : "",
+          efi_enabled(EFI_RS) ? " EFI" : "",
+          !cmos_rtc_probe
+              ? "Try with command line option \"cmos-rtc-probe\"\n"
+              : !efi_enabled(EFI_RS)
+                  ? "System must be booted from EFI\n"
+                  : "");
+}
+
+static unsigned long get_wallclock_time(void)
+{
+    switch ( wallclock_source )
+    {
+    case WALLCLOCK_XEN:
         return read_xen_wallclock();
 
-    return get_cmos_time();
+    case WALLCLOCK_CMOS:
+        return cmos_read();
+
+    case WALLCLOCK_EFI:
+        return efi_get_time();
+
+    case WALLCLOCK_UNSET:
+        /* Unexpected state - handled by the ASSERT_UNREACHABLE() below. */
+        break;
+    }
+
+    ASSERT_UNREACHABLE();
+    return 0;
 }
 
 /***************************************************************************
@@ -2462,6 +2528,10 @@ int __init init_xen_time(void)
 
     open_softirq(TIME_CALIBRATE_SOFTIRQ, local_time_calibration);
 
+    probe_wallclock();
+
+    printk(XENLOG_INFO "Wallclock source: %s\n", wallclock_type_to_string());
+
     /* NB. get_wallclock_time() can take over one second to execute. */
     do_settime(get_wallclock_time(), 0, NOW());
 
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 5/6] x86/time: introduce command line option to select wallclock
  2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
                   ` (3 preceding siblings ...)
  2024-09-04 15:31 ` [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock Roger Pau Monne
@ 2024-09-04 15:31 ` Roger Pau Monne
  2024-09-04 15:31 ` [PATCH v4 6/6] x86/time: prefer CMOS over EFI_GET_TIME Roger Pau Monne
  5 siblings, 0 replies; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Andrew Cooper, Jan Beulich, Julien Grall, Stefano Stabellini

Allow setting the used wallclock from the command line.  When the option is set
to a value different than `auto` the probing is bypassed and the selected
implementation is used (as long as it's available).

The `xen` and `efi` options require being booted as a Xen guest (with Xen guest
supported built-in) or from UEFI firmware.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v3:
 - Note xen option is only available if Xen guest support it built.
 - Fix typo.
---
 docs/misc/xen-command-line.pandoc | 19 ++++++++++++++++++
 xen/arch/x86/time.c               | 33 ++++++++++++++++++++++++++++++-
 2 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/docs/misc/xen-command-line.pandoc b/docs/misc/xen-command-line.pandoc
index 0a66e1ee2d7e..1944b9d8eb9d 100644
--- a/docs/misc/xen-command-line.pandoc
+++ b/docs/misc/xen-command-line.pandoc
@@ -2821,6 +2821,25 @@ vwfi to `native` reduces irq latency significantly. It can also lead to
 suboptimal scheduling decisions, but only when the system is
 oversubscribed (i.e., in total there are more vCPUs than pCPUs).
 
+### wallclock (x86)
+> `= auto | xen | cmos | efi`
+
+> Default: `auto`
+
+Allow forcing the usage of a specific wallclock source.
+
+ * `auto` let the hypervisor select the clocksource based on internal
+   heuristics.
+
+ * `xen` force usage of the Xen shared_info wallclock when booted as a Xen
+   guest.  This option is only available if the hypervisor was compiled with
+   `CONFIG_XEN_GUEST` enabled.
+
+ * `cmos` force usage of the CMOS RTC wallclock.
+
+ * `efi` force usage of the EFI_GET_TIME run-time method when booted from EFI
+   firmware.
+
 ### watchdog (x86)
 > `= force | <boolean>`
 
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 9ebeee61b987..52944b8fbfde 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -1553,6 +1553,36 @@ static const char *__init wallclock_type_to_string(void)
     return "";
 }
 
+static int __init cf_check parse_wallclock(const char *arg)
+{
+    if ( !arg )
+        return -EINVAL;
+
+    if ( !strcmp("auto", arg) )
+        wallclock_source = WALLCLOCK_UNSET;
+    else if ( !strcmp("xen", arg) )
+    {
+        if ( !xen_guest )
+            return -EINVAL;
+
+        wallclock_source = WALLCLOCK_XEN;
+    }
+    else if ( !strcmp("cmos", arg) )
+        wallclock_source = WALLCLOCK_CMOS;
+    else if ( !strcmp("efi", arg) )
+    {
+        if ( !efi_enabled(EFI_RS) )
+            return -EINVAL;
+
+        wallclock_source = WALLCLOCK_EFI;
+    }
+    else
+        return -EINVAL;
+
+    return 0;
+}
+custom_param("wallclock", parse_wallclock);
+
 static void __init probe_wallclock(void)
 {
     ASSERT(wallclock_source == WALLCLOCK_UNSET);
@@ -2528,7 +2558,8 @@ int __init init_xen_time(void)
 
     open_softirq(TIME_CALIBRATE_SOFTIRQ, local_time_calibration);
 
-    probe_wallclock();
+    if ( wallclock_source == WALLCLOCK_UNSET )
+        probe_wallclock();
 
     printk(XENLOG_INFO "Wallclock source: %s\n", wallclock_type_to_string());
 
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* [PATCH v4 6/6] x86/time: prefer CMOS over EFI_GET_TIME
  2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
                   ` (4 preceding siblings ...)
  2024-09-04 15:31 ` [PATCH v4 5/6] x86/time: introduce command line option to select wallclock Roger Pau Monne
@ 2024-09-04 15:31 ` Roger Pau Monne
  5 siblings, 0 replies; 13+ messages in thread
From: Roger Pau Monne @ 2024-09-04 15:31 UTC (permalink / raw)
  To: xen-devel
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Roger Pau Monne,
	Jan Beulich, Andrew Cooper

The EFI_GET_TIME implementation is well known to be broken for many firmware
implementations, for Xen the result on such implementations are:

----[ Xen-4.19-unstable  x86_64  debug=y  Tainted:   C    ]----
CPU:    0
RIP:    e008:[<0000000062ccfa70>] 0000000062ccfa70
[...]
Xen call trace:
   [<0000000062ccfa70>] R 0000000062ccfa70
   [<00000000732e9a3f>] S 00000000732e9a3f
   [<ffff82d04034f34f>] F arch/x86/time.c#get_cmos_time+0x1b3/0x26e
   [<ffff82d04045926f>] F init_xen_time+0x28/0xa4
   [<ffff82d040454bc4>] F __start_xen+0x1ee7/0x2578
   [<ffff82d040203334>] F __high_start+0x94/0xa0

Pagetable walk from 0000000062ccfa70:
 L4[0x000] = 000000207ef1c063 ffffffffffffffff
 L3[0x001] = 000000005d6c0063 ffffffffffffffff
 L2[0x116] = 8000000062c001e3 ffffffffffffffff (PSE)

****************************************
Panic on CPU 0:
FATAL PAGE FAULT
[error_code=0011]
Faulting linear address: 0000000062ccfa70
****************************************

Swap the preference to default to CMOS first, and EFI later, in an attempt to
use EFI_GET_TIME as a last resort option only.  Note that Linux for example
doesn't allow calling the get_time method, and instead provides a dummy handler
that unconditionally returns EFI_UNSUPPORTED on x86-64.

Such change in the preferences requires some re-arranging of the function
logic, so that panic messages with workaround suggestions are suitably printed.

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
---
Changes since v2:
 - Updated to match previous changes.
---
 xen/arch/x86/time.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 52944b8fbfde..788a12d52fc3 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -1592,14 +1592,14 @@ static void __init probe_wallclock(void)
         wallclock_source = WALLCLOCK_XEN;
         return;
     }
-    if ( efi_enabled(EFI_RS) && efi_get_time() )
+    if ( cmos_probe() )
     {
-        wallclock_source = WALLCLOCK_EFI;
+        wallclock_source = WALLCLOCK_CMOS;
         return;
     }
-    if ( cmos_probe() )
+    if ( efi_enabled(EFI_RS) && efi_get_time() )
     {
-        wallclock_source = WALLCLOCK_CMOS;
+        wallclock_source = WALLCLOCK_EFI;
         return;
     }
 
-- 
2.46.0



^ permalink raw reply related	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest
  2024-09-04 15:31 ` [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest Roger Pau Monne
@ 2024-09-05 15:45   ` Jan Beulich
  2024-09-09 10:23     ` Roger Pau Monné
  0 siblings, 1 reply; 13+ messages in thread
From: Jan Beulich @ 2024-09-05 15:45 UTC (permalink / raw)
  To: Roger Pau Monne
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Andrew Cooper,
	xen-devel

On 04.09.2024 17:31, Roger Pau Monne wrote:
> Move the current code in get_wallclock_time() to fetch the Xen wallclock
> information from the shared page when running as a guest into a separate
> helper.
> 
> No functional change intended.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>

Acked-by: Jan Beulich <jbeulich@suse.com>

Still ...

> --- a/xen/arch/x86/time.c
> +++ b/xen/arch/x86/time.c
> @@ -787,6 +787,30 @@ static struct platform_timesource __initdata_cf_clobber plt_xen_timer =
>  };
>  #endif
>  
> +static unsigned long read_xen_wallclock(void)
> +{
> +#ifdef CONFIG_XEN_GUEST
> +    struct shared_info *sh_info = XEN_shared_info;

... I'd like to switch this to pointer-to-const while committing, if okay
with you.

Jan


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 2/6] x86/time: move CMOS edge detection into read helper
  2024-09-04 15:31 ` [PATCH v4 2/6] x86/time: move CMOS edge detection into read helper Roger Pau Monne
@ 2024-09-05 15:46   ` Jan Beulich
  0 siblings, 0 replies; 13+ messages in thread
From: Jan Beulich @ 2024-09-05 15:46 UTC (permalink / raw)
  To: Roger Pau Monne
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Andrew Cooper,
	xen-devel

On 04.09.2024 17:31, Roger Pau Monne wrote:
> Move the logic that ensures the CMOS RTC data is read just after it's been
> updated into the __get_cmos_time() function that does the register reads.  This
> requires returning a boolean from __get_cmos_time() to signal whether the read
> has been successfully performed after an update.
> 
> Note that while __get_cmos_time() can be used without waiting for the update
> edge, so far the only caller does wait for it, hence move the code inside of
> the function.
> 
> The goal, albeit not accomplished by this patch, is to be able to split the
> probing and the reading of the CMOS RTC data into two separate functions.
> 
> No functional change intended.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>

Acked-by: Jan Beulich <jbeulich@suse.com>




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 3/6] x86/time: split CMOS read and probe logic into function
  2024-09-04 15:31 ` [PATCH v4 3/6] x86/time: split CMOS read and probe logic into function Roger Pau Monne
@ 2024-09-05 15:49   ` Jan Beulich
  0 siblings, 0 replies; 13+ messages in thread
From: Jan Beulich @ 2024-09-05 15:49 UTC (permalink / raw)
  To: Roger Pau Monne
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Andrew Cooper,
	xen-devel

On 04.09.2024 17:31, Roger Pau Monne wrote:
> The current logic to probe for the CMOS RTC is open-coded in get_cmos_time(),
> move it to a separate function that both serves the purpose of testing for the
> CMOS RTC existence and returning its value.
> 
> The goal is to be able to split the probing and the reading logic into separate
> helpers, and putting the current logic in a separate function helps simplifying
> further changes.
> 
> A transient *rtc_p variable is introduced as a parameter to the function, that
> will be removed by further changes.  Also note that due to the code movement,
> now cmos_rtc_probe will only get cleared on a second call to get_cmos_time(),
> as the newly introduced cmos_probe() function doesn't modify the variable
> anymore.
> 
> No functional change intended.
> 
> Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>

Acked-by: Jan Beulich <jbeulich@suse.com>




^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock
  2024-09-04 15:31 ` [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock Roger Pau Monne
@ 2024-09-05 15:58   ` Jan Beulich
  2024-09-09 11:02     ` Roger Pau Monné
  0 siblings, 1 reply; 13+ messages in thread
From: Jan Beulich @ 2024-09-05 15:58 UTC (permalink / raw)
  To: Roger Pau Monne
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Andrew Cooper,
	xen-devel

On 04.09.2024 17:31, Roger Pau Monne wrote:
> --- a/xen/arch/x86/time.c
> +++ b/xen/arch/x86/time.c
> @@ -1291,14 +1291,23 @@ static bool __get_cmos_time(struct rtc_time *rtc)
>      return t1 <= SECONDS(1) && t2 < MILLISECS(3);
>  }
>  
> -static bool cmos_probe(struct rtc_time *rtc_p, bool cmos_rtc_probe)
> +static bool __initdata cmos_rtc_probe;
> +boolean_param("cmos-rtc-probe", cmos_rtc_probe);
> +
> +static bool __init cmos_probe(void)

I'm sorry for not paying attention to this earlier, but "cmos" alone
is misleading here and perhaps even more so for cmos_read(). These
aren't about the CMOS (storage) but the CMOS RTC. May I suggest
cmos_rtc_{probe,read}() instead?

>  {
>      unsigned int seconds = 60;
>  
> +    if ( !(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) )
> +        return true;
> +
> +    if ( !cmos_rtc_probe )
> +        return false;

With this I think ...

>      for ( ; ; )
>      {
> -        bool success = __get_cmos_time(rtc_p);
> -        struct rtc_time rtc = *rtc_p;
> +        struct rtc_time rtc;
> +        bool success = __get_cmos_time(&rtc);
>  
>          if ( likely(!cmos_rtc_probe) )
>              return true;

... this ends up being dead code.

Jan


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest
  2024-09-05 15:45   ` Jan Beulich
@ 2024-09-09 10:23     ` Roger Pau Monné
  0 siblings, 0 replies; 13+ messages in thread
From: Roger Pau Monné @ 2024-09-09 10:23 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Andrew Cooper,
	xen-devel

On Thu, Sep 05, 2024 at 05:45:20PM +0200, Jan Beulich wrote:
> On 04.09.2024 17:31, Roger Pau Monne wrote:
> > Move the current code in get_wallclock_time() to fetch the Xen wallclock
> > information from the shared page when running as a guest into a separate
> > helper.
> > 
> > No functional change intended.
> > 
> > Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
> 
> Acked-by: Jan Beulich <jbeulich@suse.com>
> 
> Still ...
> 
> > --- a/xen/arch/x86/time.c
> > +++ b/xen/arch/x86/time.c
> > @@ -787,6 +787,30 @@ static struct platform_timesource __initdata_cf_clobber plt_xen_timer =
> >  };
> >  #endif
> >  
> > +static unsigned long read_xen_wallclock(void)
> > +{
> > +#ifdef CONFIG_XEN_GUEST
> > +    struct shared_info *sh_info = XEN_shared_info;
> 
> ... I'd like to switch this to pointer-to-const while committing, if okay
> with you.

Oh, sure.

Thanks, Roger.


^ permalink raw reply	[flat|nested] 13+ messages in thread

* Re: [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock
  2024-09-05 15:58   ` Jan Beulich
@ 2024-09-09 11:02     ` Roger Pau Monné
  0 siblings, 0 replies; 13+ messages in thread
From: Roger Pau Monné @ 2024-09-09 11:02 UTC (permalink / raw)
  To: Jan Beulich
  Cc: Daniel P. Smith, Marek Marczykowski-Górecki, Andrew Cooper,
	xen-devel

On Thu, Sep 05, 2024 at 05:58:47PM +0200, Jan Beulich wrote:
> On 04.09.2024 17:31, Roger Pau Monne wrote:
> > --- a/xen/arch/x86/time.c
> > +++ b/xen/arch/x86/time.c
> > @@ -1291,14 +1291,23 @@ static bool __get_cmos_time(struct rtc_time *rtc)
> >      return t1 <= SECONDS(1) && t2 < MILLISECS(3);
> >  }
> >  
> > -static bool cmos_probe(struct rtc_time *rtc_p, bool cmos_rtc_probe)
> > +static bool __initdata cmos_rtc_probe;
> > +boolean_param("cmos-rtc-probe", cmos_rtc_probe);
> > +
> > +static bool __init cmos_probe(void)
> 
> I'm sorry for not paying attention to this earlier, but "cmos" alone
> is misleading here and perhaps even more so for cmos_read(). These
> aren't about the CMOS (storage) but the CMOS RTC. May I suggest
> cmos_rtc_{probe,read}() instead?

I've assumed that those living in time.c would be clear enough it's
the CMOS RTC, but I'm fine with renaming to cmos_rtc_{probe,read}().

> 
> >  {
> >      unsigned int seconds = 60;
> >  
> > +    if ( !(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) )
> > +        return true;
> > +
> > +    if ( !cmos_rtc_probe )
> > +        return false;
> 
> With this I think ...
> 
> >      for ( ; ; )
> >      {
> > -        bool success = __get_cmos_time(rtc_p);
> > -        struct rtc_time rtc = *rtc_p;
> > +        struct rtc_time rtc;
> > +        bool success = __get_cmos_time(&rtc);
> >  
> >          if ( likely(!cmos_rtc_probe) )
> >              return true;
> 
> ... this ends up being dead code.

Indeed, I've missed to remove that one when moving the check outside
of the for loop.

Thanks, Roger.


^ permalink raw reply	[flat|nested] 13+ messages in thread

end of thread, other threads:[~2024-09-09 11:03 UTC | newest]

Thread overview: 13+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-09-04 15:31 [PATCH v4 0/6] x86/time: improvements to wallclock logic Roger Pau Monne
2024-09-04 15:31 ` [PATCH v4 1/6] x86/time: introduce helper to fetch Xen wallclock when running as a guest Roger Pau Monne
2024-09-05 15:45   ` Jan Beulich
2024-09-09 10:23     ` Roger Pau Monné
2024-09-04 15:31 ` [PATCH v4 2/6] x86/time: move CMOS edge detection into read helper Roger Pau Monne
2024-09-05 15:46   ` Jan Beulich
2024-09-04 15:31 ` [PATCH v4 3/6] x86/time: split CMOS read and probe logic into function Roger Pau Monne
2024-09-05 15:49   ` Jan Beulich
2024-09-04 15:31 ` [PATCH v4 4/6] x86/time: introduce probing logic for the wallclock Roger Pau Monne
2024-09-05 15:58   ` Jan Beulich
2024-09-09 11:02     ` Roger Pau Monné
2024-09-04 15:31 ` [PATCH v4 5/6] x86/time: introduce command line option to select wallclock Roger Pau Monne
2024-09-04 15:31 ` [PATCH v4 6/6] x86/time: prefer CMOS over EFI_GET_TIME Roger Pau Monne

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.