[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH] x86/ACPI: allow CMOS RTC use even when ACPI says there is none
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@xxxxxxxx> > > --- 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); > } > > /*************************************************************************** > > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |