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>
This commit is contained in:
parent
3c4fbe5e01
commit
38c052f8cf
1 changed files with 4 additions and 8 deletions
|
@ -15,6 +15,7 @@
|
||||||
#include <linux/mc146818rtc.h>
|
#include <linux/mc146818rtc.h>
|
||||||
#include <linux/rtc.h>
|
#include <linux/rtc.h>
|
||||||
#include <linux/bcd.h>
|
#include <linux/bcd.h>
|
||||||
|
#include <linux/delay.h>
|
||||||
|
|
||||||
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
#define RTC_PIE 0x40 /* periodic interrupt enable */
|
||||||
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
#define RTC_AIE 0x20 /* alarm interrupt enable */
|
||||||
|
@ -43,7 +44,6 @@ static inline unsigned char rtc_is_updating(void)
|
||||||
|
|
||||||
static inline unsigned int get_rtc_time(struct rtc_time *time)
|
static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||||
{
|
{
|
||||||
unsigned long uip_watchdog = jiffies;
|
|
||||||
unsigned char ctrl;
|
unsigned char ctrl;
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
|
||||||
|
@ -53,19 +53,15 @@ static inline unsigned int get_rtc_time(struct rtc_time *time)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* read RTC once any update in progress is done. The update
|
* 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.
|
* 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
|
* If you need to know *exactly* when a second has started, enable
|
||||||
* periodic update complete interrupts, (via ioctl) and then
|
* periodic update complete interrupts, (via ioctl) and then
|
||||||
* immediately read /dev/rtc which will block until you get the IRQ.
|
* immediately read /dev/rtc which will block until you get the IRQ.
|
||||||
* Once the read clears, read the RTC time (again via ioctl). Easy.
|
* Once the read clears, read the RTC time (again via ioctl). Easy.
|
||||||
*/
|
*/
|
||||||
|
if (rtc_is_updating())
|
||||||
if (rtc_is_updating() != 0)
|
mdelay(20);
|
||||||
while (jiffies - uip_watchdog < 2*HZ/100) {
|
|
||||||
barrier();
|
|
||||||
cpu_relax();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Only the values that we read from the RTC are set. We leave
|
* Only the values that we read from the RTC are set. We leave
|
||||||
|
|
Loading…
Reference in a new issue