diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-08-23 17:59:07 +0200 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2008-10-08 19:44:41 -0700 |
commit | 80ad012478ee989402ac014aab956e4534acd498 (patch) | |
tree | 5b538ac1416beb89f092c5241797db7c07f6aaa5 | |
parent | f54fd05032fea1808f5e76dc8a94cde40f5d9f01 (diff) |
rtc: fix deadlock
commit 38c052f8cff1bd323ccfa968136a9556652ee420 upstream
if get_rtc_time() is _ever_ called with IRQs off, we deadlock badly
in it, waiting for jiffies to increment.
So make the code more robust by doing an explicit mdelay(20).
This solves a very hard to reproduce/debug hard lockup reported
by Mikael Pettersson.
Reported-by: Mikael Pettersson <mikpe@it.uu.se>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
-rw-r--r-- | include/asm-generic/rtc.h | 12 |
1 files changed, 4 insertions, 8 deletions
diff --git a/include/asm-generic/rtc.h b/include/asm-generic/rtc.h index dd1bed860e64..85286fb36237 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h @@ -17,6 +17,7 @@ #include <linux/mc146818rtc.h> #include <linux/rtc.h> #include <linux/bcd.h> +#include <linux/delay.h> #define RTC_PIE 0x40 /* periodic interrupt enable */ #define RTC_AIE 0x20 /* alarm interrupt enable */ @@ -45,7 +46,6 @@ static inline unsigned char rtc_is_updating(void) static inline unsigned int get_rtc_time(struct rtc_time *time) { - unsigned long uip_watchdog = jiffies; unsigned char ctrl; unsigned long flags; @@ -55,19 +55,15 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) /* * read RTC once any update in progress is done. The update - * can take just over 2ms. We wait 10 to 20ms. There is no need to + * can take just over 2ms. We wait 20ms. There is no need to * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. * If you need to know *exactly* when a second has started, enable * periodic update complete interrupts, (via ioctl) and then * immediately read /dev/rtc which will block until you get the IRQ. * Once the read clears, read the RTC time (again via ioctl). Easy. */ - - if (rtc_is_updating() != 0) - while (jiffies - uip_watchdog < 2*HZ/100) { - barrier(); - cpu_relax(); - } + if (rtc_is_updating()) + mdelay(20); /* * Only the values that we read from the RTC are set. We leave |