From: Andrew Cooper <andrew.cooper3@citrix.com>
To: Jan Beulich <JBeulich@suse.com>,
xen-devel <xen-devel@lists.xenproject.org>
Cc: Tim Deegan <tim@xen.org>, Keir Fraser <keir@xen.org>
Subject: Re: [PATCH] x86/ACPI: allow CMOS RTC use even when ACPI says there is none
Date: Mon, 28 Jul 2014 13:40:15 +0100 [thread overview]
Message-ID: <53D644AF.8000801@citrix.com> (raw)
In-Reply-To: <53D28C91020000780002613E@mail.emea.novell.com>
On 25/07/14 15:57, 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.
>
> Signed-off-by: Jan Beulich <jbeulich@suse.com>
>
> --- 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,58 @@ 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 ( 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\")");
> +
> + 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) );
Can we not break early if we exceed 1 second an have not seen an UIP ?
> +
> + 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);
> +
> + 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 )
Seconds doesn't appear to be updated before this point, meaning that we
will reprobe even if we find a plausible RTC.
> + {
> + 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");
What happens in the case that we broke because of the validity checks
for t1,t2 or rtc ? Do we want to differentiate between "no RTC" and
"RTC giving bogus values" ?
~Andrew
>
> - spin_unlock_irqrestore(&rtc_lock, flags);
> - return res;
> + return mktime(rtc.year, rtc.mon, rtc.day, rtc.hour, rtc.min, rtc.sec);
> }
>
> /***************************************************************************
>
>
next prev parent reply other threads:[~2014-07-28 12:40 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-07-25 14:57 [PATCH] x86/ACPI: allow CMOS RTC use even when ACPI says there is none Jan Beulich
2014-07-28 12:40 ` Andrew Cooper [this message]
2014-07-28 12:47 ` Jan Beulich
2014-07-28 13:04 ` Andrew Cooper
2014-07-28 13:32 ` Jan Beulich
2014-07-28 13:46 ` Andrew Cooper
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=53D644AF.8000801@citrix.com \
--to=andrew.cooper3@citrix.com \
--cc=JBeulich@suse.com \
--cc=keir@xen.org \
--cc=tim@xen.org \
--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.