Commit 38c052f8cff1bd323ccfa968136a9556652ee420
1 parent
3c4fbe5e01
Exists in
master
and in
7 other branches
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>
Showing 1 changed file with 4 additions and 8 deletions Side-by-side Diff
include/asm-generic/rtc.h
... | ... | @@ -15,6 +15,7 @@ |
15 | 15 | #include <linux/mc146818rtc.h> |
16 | 16 | #include <linux/rtc.h> |
17 | 17 | #include <linux/bcd.h> |
18 | +#include <linux/delay.h> | |
18 | 19 | |
19 | 20 | #define RTC_PIE 0x40 /* periodic interrupt enable */ |
20 | 21 | #define RTC_AIE 0x20 /* alarm interrupt enable */ |
... | ... | @@ -43,7 +44,6 @@ |
43 | 44 | |
44 | 45 | static inline unsigned int get_rtc_time(struct rtc_time *time) |
45 | 46 | { |
46 | - unsigned long uip_watchdog = jiffies; | |
47 | 47 | unsigned char ctrl; |
48 | 48 | unsigned long flags; |
49 | 49 | |
50 | 50 | |
... | ... | @@ -53,19 +53,15 @@ |
53 | 53 | |
54 | 54 | /* |
55 | 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 | 57 | * to poll-wait (up to 1s - eeccch) for the falling edge of RTC_UIP. |
58 | 58 | * If you need to know *exactly* when a second has started, enable |
59 | 59 | * periodic update complete interrupts, (via ioctl) and then |
60 | 60 | * immediately read /dev/rtc which will block until you get the IRQ. |
61 | 61 | * Once the read clears, read the RTC time (again via ioctl). Easy. |
62 | 62 | */ |
63 | - | |
64 | - if (rtc_is_updating() != 0) | |
65 | - while (jiffies - uip_watchdog < 2*HZ/100) { | |
66 | - barrier(); | |
67 | - cpu_relax(); | |
68 | - } | |
63 | + if (rtc_is_updating()) | |
64 | + mdelay(20); | |
69 | 65 | |
70 | 66 | /* |
71 | 67 | * Only the values that we read from the RTC are set. We leave |