diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-08-23 11:59:07 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-08-23 12:02:18 -0400 |
commit | 38c052f8cff1bd323ccfa968136a9556652ee420 (patch) | |
tree | 6cee3c0384438e13f065d196195a5d46a3941e4b | |
parent | 3c4fbe5e01d7e5309be5045e7ae0db20a049e6dc (diff) |
rtc: fix deadlock
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>
-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 be4af0029ac0..71ef3f0b9685 100644 --- a/include/asm-generic/rtc.h +++ b/include/asm-generic/rtc.h | |||
@@ -15,6 +15,7 @@ | |||
15 | #include <linux/mc146818rtc.h> | 15 | #include <linux/mc146818rtc.h> |
16 | #include <linux/rtc.h> | 16 | #include <linux/rtc.h> |
17 | #include <linux/bcd.h> | 17 | #include <linux/bcd.h> |
18 | #include <linux/delay.h> | ||
18 | 19 | ||
19 | #define RTC_PIE 0x40 /* periodic interrupt enable */ | 20 | #define RTC_PIE 0x40 /* periodic interrupt enable */ |
20 | #define RTC_AIE 0x20 /* alarm interrupt enable */ | 21 | #define RTC_AIE 0x20 /* alarm interrupt enable */ |
@@ -43,7 +44,6 @@ static inline unsigned char rtc_is_updating(void) | |||
43 | 44 | ||
44 | static inline unsigned int get_rtc_time(struct rtc_time *time) | 45 | static inline unsigned int get_rtc_time(struct rtc_time *time) |
45 | { | 46 | { |
46 | unsigned long uip_watchdog = jiffies; | ||
47 | unsigned char ctrl; | 47 | unsigned char ctrl; |
48 | unsigned long flags; | 48 | unsigned long flags; |
49 | 49 | ||
@@ -53,19 +53,15 @@ static inline unsigned int get_rtc_time(struct rtc_time *time) | |||
53 | 53 | ||
54 | /* | 54 | /* |
55 | * read RTC once any update in progress is done. The update | 55 | * read RTC once any update in progress is done. The update |
56 | * can take just over 2ms. We wait 10 to 20ms. There is no need to | 56 | * can take just over 2ms. We wait 20ms. There is no need to |
57 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. | 57 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. |
58 | * If you need to know *exactly* when a second has started, enable | 58 | * If you need to know *exactly* when a second has started, enable |
59 | * periodic update complete interrupts, (via ioctl) and then | 59 | * periodic update complete interrupts, (via ioctl) and then |
60 | * immediately read /dev/rtc which will block until you get the IRQ. | 60 | * immediately read /dev/rtc which will block until you get the IRQ. |
61 | * Once the read clears, read the RTC time (again via ioctl). Easy. | 61 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
62 | */ | 62 | */ |
63 | 63 | if (rtc_is_updating()) | |
64 | if (rtc_is_updating() != 0) | 64 | mdelay(20); |
65 | while (jiffies - uip_watchdog < 2*HZ/100) { | ||
66 | barrier(); | ||
67 | cpu_relax(); | ||
68 | } | ||
69 | 65 | ||
70 | /* | 66 | /* |
71 | * Only the values that we read from the RTC are set. We leave | 67 | * Only the values that we read from the RTC are set. We leave |