All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC] x86/ACPI: allow CMOS RTC use even when ACPI says there is none
@ 2014-06-26 10:28 Jan Beulich
  2014-06-26 11:12 ` Tim Deegan
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Beulich @ 2014-06-26 10:28 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 5218 bytes --]

HP is setting the ACPI_FADT_NO_CMOS_RTC flag on newer systems,
regardless of whether they're being booted from UEFI. Add a command
line option to allow probing for a working RTC in that case.

Note that this still has some debugging code (//temp) in it (and no
S-o-b for that reason).

--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -218,6 +218,14 @@ If set, override Xen's calculation of th
 
 If set, override Xen's default choice for the platform timer.
 
+### cmos-rtc-probe
+> `= <boolean>`
+
+> Default: `false`
+
+Flag to indicate whether to probe for a CMOS Real Time Clock irrespective of
+ACPI indicating none to be there.
+
 ### com1,com2
 > `= <baud>[/<clock_hz>][,[DPS][,[<io-base>|pci|amt][,[<irq>][,[<port-bdf>][,[<bridge-bdf>]]]]]]`
 
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -654,37 +654,40 @@ mktime (unsigned int year, unsigned int 
         )*60 + sec; /* finally seconds */
 }
 
-static unsigned long __get_cmos_time(void)
-{
+struct rtc_time {
     unsigned int year, mon, day, hour, min, sec;
+};
 
-    sec  = CMOS_READ(RTC_SECONDS);
-    min  = CMOS_READ(RTC_MINUTES);
-    hour = CMOS_READ(RTC_HOURS);
-    day  = CMOS_READ(RTC_DAY_OF_MONTH);
-    mon  = CMOS_READ(RTC_MONTH);
-    year = CMOS_READ(RTC_YEAR);
+static void __get_cmos_time(struct rtc_time *rtc)
+{
+    rtc->sec  = CMOS_READ(RTC_SECONDS);
+    rtc->min  = CMOS_READ(RTC_MINUTES);
+    rtc->hour = CMOS_READ(RTC_HOURS);
+    rtc->day  = CMOS_READ(RTC_DAY_OF_MONTH);
+    rtc->mon  = CMOS_READ(RTC_MONTH);
+    rtc->year = CMOS_READ(RTC_YEAR);
     
     if ( RTC_ALWAYS_BCD || !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) )
     {
-        BCD_TO_BIN(sec);
-        BCD_TO_BIN(min);
-        BCD_TO_BIN(hour);
-        BCD_TO_BIN(day);
-        BCD_TO_BIN(mon);
-        BCD_TO_BIN(year);
+        BCD_TO_BIN(rtc->sec);
+        BCD_TO_BIN(rtc->min);
+        BCD_TO_BIN(rtc->hour);
+        BCD_TO_BIN(rtc->day);
+        BCD_TO_BIN(rtc->mon);
+        BCD_TO_BIN(rtc->year);
     }
 
-    if ( (year += 1900) < 1970 )
-        year += 100;
-
-    return mktime(year, mon, day, hour, min, sec);
+    if ( (rtc->year += 1900) < 1970 )
+        rtc->year += 100;
 }
 
 static unsigned long get_cmos_time(void)
 {
     unsigned long res, flags;
-    int i;
+    struct rtc_time rtc;
+    unsigned int seconds = 60;
+    static bool_t __read_mostly cmos_rtc_probe;
+    boolean_param("cmos-rtc-probe", cmos_rtc_probe);
 
     if ( efi_enabled )
     {
@@ -693,23 +696,60 @@ static unsigned long get_cmos_time(void)
             return res;
     }
 
-    if ( unlikely(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) )
-        panic("System without CMOS RTC must be booted from EFI");
-
-    spin_lock_irqsave(&rtc_lock, flags);
-
-    /* read RTC exactly on falling edge of update flag */
-    for ( i = 0 ; i < 1000000 ; i++ ) /* may take up to 1 second... */
-        if ( (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) )
+    if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) )
+        cmos_rtc_probe = 0;
+    else if ( unlikely(!cmos_rtc_probe) )
+        panic("System with no CMOS RTC advertised must be booted from EFI"
+              " or with command line option \"cmos-rtc-probe\"");
+cmos_rtc_probe = 1;//temp
+
+    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);
+printk("RTC: %04u-%02u-%02u %02u:%02u:%02u (%lu/%lu)\n", rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec, t1, t2);//temp
+
+        if ( likely(!cmos_rtc_probe) ||
+             t1 > SECONDS(1) || t2 >= MILLISECS(3) ||
+             rtc.sec >= 60 || rtc.min >= 60 || rtc.hour >= 24 ||
+             !rtc.day || rtc.day > 31 ||
+             !rtc.mon || rtc.mon > 12 )
             break;
-    for ( i = 0 ; i < 1000000 ; i++ ) /* must try at least 2.228 ms */
-        if ( !(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) )
+
+        if ( seconds < 60 )
+        {
+            if ( rtc.sec != seconds )
+                cmos_rtc_probe = 0;
             break;
+        }
+
+        process_pending_softirqs();
+
+        seconds = rtc.sec;
+    }
 
-    res = __get_cmos_time();
+    if ( unlikely(cmos_rtc_probe) )
+        panic("No CMOS RTC found - system must be booted from EFI");
 
-    spin_unlock_irqrestore(&rtc_lock, flags);
-    return res;
+    return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec);
 }
 
 /***************************************************************************


[-- Attachment #2: x86-RTC-probe.patch --]
[-- Type: text/plain, Size: 5282 bytes --]

x86/ACPI: allow CMOS RTC use even when ACPI says there is none

HP is setting the ACPI_FADT_NO_CMOS_RTC flag on newer systems,
regardless of whether they're being booted from UEFI. Add a command
line option to allow probing for a working RTC in that case.

Note that this still has some debugging code (//temp) in it (and no
S-o-b for that reason).

--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -218,6 +218,14 @@ If set, override Xen's calculation of th
 
 If set, override Xen's default choice for the platform timer.
 
+### cmos-rtc-probe
+> `= <boolean>`
+
+> Default: `false`
+
+Flag to indicate whether to probe for a CMOS Real Time Clock irrespective of
+ACPI indicating none to be there.
+
 ### com1,com2
 > `= <baud>[/<clock_hz>][,[DPS][,[<io-base>|pci|amt][,[<irq>][,[<port-bdf>][,[<bridge-bdf>]]]]]]`
 
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -654,37 +654,40 @@ mktime (unsigned int year, unsigned int 
         )*60 + sec; /* finally seconds */
 }
 
-static unsigned long __get_cmos_time(void)
-{
+struct rtc_time {
     unsigned int year, mon, day, hour, min, sec;
+};
 
-    sec  = CMOS_READ(RTC_SECONDS);
-    min  = CMOS_READ(RTC_MINUTES);
-    hour = CMOS_READ(RTC_HOURS);
-    day  = CMOS_READ(RTC_DAY_OF_MONTH);
-    mon  = CMOS_READ(RTC_MONTH);
-    year = CMOS_READ(RTC_YEAR);
+static void __get_cmos_time(struct rtc_time *rtc)
+{
+    rtc->sec  = CMOS_READ(RTC_SECONDS);
+    rtc->min  = CMOS_READ(RTC_MINUTES);
+    rtc->hour = CMOS_READ(RTC_HOURS);
+    rtc->day  = CMOS_READ(RTC_DAY_OF_MONTH);
+    rtc->mon  = CMOS_READ(RTC_MONTH);
+    rtc->year = CMOS_READ(RTC_YEAR);
     
     if ( RTC_ALWAYS_BCD || !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) )
     {
-        BCD_TO_BIN(sec);
-        BCD_TO_BIN(min);
-        BCD_TO_BIN(hour);
-        BCD_TO_BIN(day);
-        BCD_TO_BIN(mon);
-        BCD_TO_BIN(year);
+        BCD_TO_BIN(rtc->sec);
+        BCD_TO_BIN(rtc->min);
+        BCD_TO_BIN(rtc->hour);
+        BCD_TO_BIN(rtc->day);
+        BCD_TO_BIN(rtc->mon);
+        BCD_TO_BIN(rtc->year);
     }
 
-    if ( (year += 1900) < 1970 )
-        year += 100;
-
-    return mktime(year, mon, day, hour, min, sec);
+    if ( (rtc->year += 1900) < 1970 )
+        rtc->year += 100;
 }
 
 static unsigned long get_cmos_time(void)
 {
     unsigned long res, flags;
-    int i;
+    struct rtc_time rtc;
+    unsigned int seconds = 60;
+    static bool_t __read_mostly cmos_rtc_probe;
+    boolean_param("cmos-rtc-probe", cmos_rtc_probe);
 
     if ( efi_enabled )
     {
@@ -693,23 +696,60 @@ static unsigned long get_cmos_time(void)
             return res;
     }
 
-    if ( unlikely(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC) )
-        panic("System without CMOS RTC must be booted from EFI");
-
-    spin_lock_irqsave(&rtc_lock, flags);
-
-    /* read RTC exactly on falling edge of update flag */
-    for ( i = 0 ; i < 1000000 ; i++ ) /* may take up to 1 second... */
-        if ( (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) )
+    if ( likely(!(acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_CMOS_RTC)) )
+        cmos_rtc_probe = 0;
+    else if ( unlikely(!cmos_rtc_probe) )
+        panic("System with no CMOS RTC advertised must be booted from EFI"
+              " or with command line option \"cmos-rtc-probe\"");
+cmos_rtc_probe = 1;//temp
+
+    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);
+printk("RTC: %04u-%02u-%02u %02u:%02u:%02u (%lu/%lu)\n", rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec, t1, t2);//temp
+
+        if ( likely(!cmos_rtc_probe) ||
+             t1 > SECONDS(1) || t2 >= MILLISECS(3) ||
+             rtc.sec >= 60 || rtc.min >= 60 || rtc.hour >= 24 ||
+             !rtc.day || rtc.day > 31 ||
+             !rtc.mon || rtc.mon > 12 )
             break;
-    for ( i = 0 ; i < 1000000 ; i++ ) /* must try at least 2.228 ms */
-        if ( !(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP) )
+
+        if ( seconds < 60 )
+        {
+            if ( rtc.sec != seconds )
+                cmos_rtc_probe = 0;
             break;
+        }
+
+        process_pending_softirqs();
+
+        seconds = rtc.sec;
+    }
 
-    res = __get_cmos_time();
+    if ( unlikely(cmos_rtc_probe) )
+        panic("No CMOS RTC found - system must be booted from EFI");
 
-    spin_unlock_irqrestore(&rtc_lock, flags);
-    return res;
+    return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec);
 }
 
 /***************************************************************************

[-- Attachment #3: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

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

* Re: [PATCH RFC] x86/ACPI: allow CMOS RTC use even when ACPI says there is none
  2014-06-26 10:28 [PATCH RFC] x86/ACPI: allow CMOS RTC use even when ACPI says there is none Jan Beulich
@ 2014-06-26 11:12 ` Tim Deegan
  2014-06-26 11:41   ` Jan Beulich
  0 siblings, 1 reply; 4+ messages in thread
From: Tim Deegan @ 2014-06-26 11:12 UTC (permalink / raw)
  To: Jan Beulich; +Cc: xen-devel

At 11:28 +0100 on 26 Jun (1403778496), Jan Beulich wrote:
> HP is setting the ACPI_FADT_NO_CMOS_RTC flag on newer systems,
> regardless of whether they're being booted from UEFI. Add a command
> line option to allow probing for a working RTC in that case.

I like this general direction.  I would add a printk in the case where
we are probing, since the probe will stall boot for >= 1 sec.

Maybe also worth checking that the times returned on the two passes
actually make sense (i.e. that the difference in RTC times matches the
difference in NOW() to within +/- 10ms).

Thirdly, since get_cmos_time() can be called more than once, I think
that just leaving cmos_rtc_probe == 0 could make us panic on the second
invocation.

Cheers,

Tim.

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

* Re: [PATCH RFC] x86/ACPI: allow CMOS RTC use even when ACPI says there is none
  2014-06-26 11:12 ` Tim Deegan
@ 2014-06-26 11:41   ` Jan Beulich
  2014-06-26 11:50     ` Tim Deegan
  0 siblings, 1 reply; 4+ messages in thread
From: Jan Beulich @ 2014-06-26 11:41 UTC (permalink / raw)
  To: Tim Deegan; +Cc: xen-devel

>>> On 26.06.14 at 13:12, <tim@xen.org> wrote:
> At 11:28 +0100 on 26 Jun (1403778496), Jan Beulich wrote:
>> HP is setting the ACPI_FADT_NO_CMOS_RTC flag on newer systems,
>> regardless of whether they're being booted from UEFI. Add a command
>> line option to allow probing for a working RTC in that case.
> 
> I like this general direction.  I would add a printk in the case where
> we are probing, since the probe will stall boot for >= 1 sec.

Right now we stall for up to 1 sec already; since the probing
doesn't happen without being asked for, I don't view it as a
problem that now we stall for up to 2 sec.

> Maybe also worth checking that the times returned on the two passes
> actually make sense (i.e. that the difference in RTC times matches the
> difference in NOW() to within +/- 10ms).

I had considered this too, but intentionally dropped the idea, so that
odd behavior when running in nested virtualization scenarios can be
avoided.

> Thirdly, since get_cmos_time() can be called more than once, I think
> that just leaving cmos_rtc_probe == 0 could make us panic on the second
> invocation.

Very good point, this definitely needs fixing. I guess I'll just amend
the condition with a system_state check.

Jan

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

* Re: [PATCH RFC] x86/ACPI: allow CMOS RTC use even when ACPI says there is none
  2014-06-26 11:41   ` Jan Beulich
@ 2014-06-26 11:50     ` Tim Deegan
  0 siblings, 0 replies; 4+ messages in thread
From: Tim Deegan @ 2014-06-26 11:50 UTC (permalink / raw)
  To: Jan Beulich; +Cc: xen-devel

At 12:41 +0100 on 26 Jun (1403782897), Jan Beulich wrote:
> >>> On 26.06.14 at 13:12, <tim@xen.org> wrote:
> > At 11:28 +0100 on 26 Jun (1403778496), Jan Beulich wrote:
> >> HP is setting the ACPI_FADT_NO_CMOS_RTC flag on newer systems,
> >> regardless of whether they're being booted from UEFI. Add a command
> >> line option to allow probing for a working RTC in that case.
> > 
> > I like this general direction.  I would add a printk in the case where
> > we are probing, since the probe will stall boot for >= 1 sec.
> 
> Right now we stall for up to 1 sec already; since the probing
> doesn't happen without being asked for, I don't view it as a
> problem that now we stall for up to 2 sec.

Ack.

> > Maybe also worth checking that the times returned on the two passes
> > actually make sense (i.e. that the difference in RTC times matches the
> > difference in NOW() to within +/- 10ms).
> 
> I had considered this too, but intentionally dropped the idea, so that
> odd behavior when running in nested virtualization scenarios can be
> avoided.

I guess so.  We'd have to be running inside a hypervisor that has the
same buggy tables as these HP machines, but OTOH anything that passes
the tests you already have looks quite a lot like an RTC. :)

Tim.

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

end of thread, other threads:[~2014-06-26 11:50 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-06-26 10:28 [PATCH RFC] x86/ACPI: allow CMOS RTC use even when ACPI says there is none Jan Beulich
2014-06-26 11:12 ` Tim Deegan
2014-06-26 11:41   ` Jan Beulich
2014-06-26 11:50     ` Tim Deegan

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.