aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid P. Reed <dpreed@reed.com>2007-11-14 20:14:50 -0500
committerThomas Gleixner <tglx@apollo.(none)>2007-11-17 10:27:01 -0500
commitbbbd99955bfe84c9ae63f51db946a7bcd21f48be (patch)
treeef9c2f2a675523fba0ae84ae7d3514d804f0ec1e
parentc399da0d97e06803e51085ec076b63a3168aad1b (diff)
x86: on x86_64, correct reading of PC RTC when update in progress in time_64.c
Correct potentially unstable PC RTC time register reading in time_64.c Stop the use of an incorrect technique for reading the standard PC RTC timer, which is documented to "disconnect" time registers from the bus while updates are in progress. The use of UIP flag while interrupts are disabled to protect a 244 microsecond window is one of the Motorola spec sheet's documented ways to read the RTC time registers reliably. tglx: removed locking changes from original patch, as they gain nothing (read_persistent_clock is only called during boot, suspend, resume - so no hot path affected) and conflict with the paravirt locking scheme (see 32bit code), which we do not want to complicate for no benefit. Signed-off-by: David P. Reed <dpreed@reed.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--arch/x86/kernel/time_64.c30
1 files changed, 18 insertions, 12 deletions
diff --git a/arch/x86/kernel/time_64.c b/arch/x86/kernel/time_64.c
index 4ad1f7a6a839..368b1942b39a 100644
--- a/arch/x86/kernel/time_64.c
+++ b/arch/x86/kernel/time_64.c
@@ -161,21 +161,27 @@ unsigned long read_persistent_clock(void)
161 unsigned century = 0; 161 unsigned century = 0;
162 162
163 spin_lock_irqsave(&rtc_lock, flags); 163 spin_lock_irqsave(&rtc_lock, flags);
164 /*
165 * if UIP is clear, then we have >= 244 microseconds before RTC
166 * registers will be updated. Spec sheet says that this is the
167 * reliable way to read RTC - registers invalid (off bus) during update
168 */
169 while ((CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
170 cpu_relax();
164 171
165 do { 172
166 sec = CMOS_READ(RTC_SECONDS); 173 /* now read all RTC registers while stable with interrupts disabled */
167 min = CMOS_READ(RTC_MINUTES); 174 sec = CMOS_READ(RTC_SECONDS);
168 hour = CMOS_READ(RTC_HOURS); 175 min = CMOS_READ(RTC_MINUTES);
169 day = CMOS_READ(RTC_DAY_OF_MONTH); 176 hour = CMOS_READ(RTC_HOURS);
170 mon = CMOS_READ(RTC_MONTH); 177 day = CMOS_READ(RTC_DAY_OF_MONTH);
171 year = CMOS_READ(RTC_YEAR); 178 mon = CMOS_READ(RTC_MONTH);
179 year = CMOS_READ(RTC_YEAR);
172#ifdef CONFIG_ACPI 180#ifdef CONFIG_ACPI
173 if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID && 181 if (acpi_gbl_FADT.header.revision >= FADT2_REVISION_ID &&
174 acpi_gbl_FADT.century) 182 acpi_gbl_FADT.century)
175 century = CMOS_READ(acpi_gbl_FADT.century); 183 century = CMOS_READ(acpi_gbl_FADT.century);
176#endif 184#endif
177 } while (sec != CMOS_READ(RTC_SECONDS));
178
179 spin_unlock_irqrestore(&rtc_lock, flags); 185 spin_unlock_irqrestore(&rtc_lock, flags);
180 186
181 /* 187 /*