Re: [patch] Real-Time Preemption, -RT-2.6.9-mm1-V0

From: Ingo Molnar
Date: Wed Oct 27 2004 - 03:52:28 EST



* Ingo Molnar <mingo@xxxxxxx> wrote:

> > does the quick hack below help?
>
> here's a more complete fix.

third time lucky?

Ingo

--- linux/drivers/char/rtc.c.orig
+++ linux/drivers/char/rtc.c
@@ -177,7 +177,7 @@ static unsigned long rtc_max_user_freq =
/*
* rtc_task_lock nests inside rtc_lock.
*/
-static DECLARE_SPINLOCK(rtc_task_lock);
+static DECLARE_RAW_SPINLOCK(rtc_task_lock);
static rtc_task_t *rtc_callback = NULL;
#endif

@@ -238,10 +238,17 @@ irqreturn_t rtc_interrupt(int irq, void
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0);
}

- if (rtc_status & RTC_TIMER_ON)
+ if (rtc_status & RTC_TIMER_ON) {
+ spin_unlock (&rtc_lock);
+ /*
+ * We do the mod_timer outside of the lock because
+ * it may reschedule under PREEMPT_REALTIME. As long
+ * as we read the flag race-free it is not a problem
+ * if two mod_timer()s race:
+ */
mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
-
- spin_unlock (&rtc_lock);
+ } else
+ spin_unlock (&rtc_lock);

/* Now do the rest of the actions */
spin_lock(&rtc_task_lock);
@@ -404,8 +411,8 @@ static int rtc_do_ioctl(unsigned int cmd
if (rtc_status & RTC_TIMER_ON) {
spin_lock_irq (&rtc_lock);
rtc_status &= ~RTC_TIMER_ON;
- del_timer(&rtc_irq_timer);
spin_unlock_irq (&rtc_lock);
+ del_timer(&rtc_irq_timer); // FIXME
}
return 0;
}
@@ -730,9 +737,10 @@ static int rtc_release(struct inode *ino
}
if (rtc_status & RTC_TIMER_ON) {
rtc_status &= ~RTC_TIMER_ON;
- del_timer(&rtc_irq_timer);
- }
- spin_unlock_irq(&rtc_lock);
+ spin_unlock_irq(&rtc_lock);
+ del_timer(&rtc_irq_timer); // FIXME
+ } else
+ spin_unlock_irq(&rtc_lock);

if (file->f_flags & FASYNC) {
rtc_fasync (-1, file, 0);
@@ -808,6 +816,7 @@ int rtc_unregister(rtc_task_t *task)
return -EIO;
#else
unsigned char tmp;
+ int rm_timer;

spin_lock_irq(&rtc_lock);
spin_lock(&rtc_task_lock);
@@ -827,13 +836,16 @@ int rtc_unregister(rtc_task_t *task)
CMOS_WRITE(tmp, RTC_CONTROL);
CMOS_READ(RTC_INTR_FLAGS);
}
+ rm_timer = 0;
if (rtc_status & RTC_TIMER_ON) {
rtc_status &= ~RTC_TIMER_ON;
- del_timer(&rtc_irq_timer);
+ rm_timer = 1;
}
rtc_status &= ~RTC_IS_OPEN;
spin_unlock(&rtc_task_lock);
spin_unlock_irq(&rtc_lock);
+ if (rm_timer)
+ del_timer(&rtc_irq_timer);
return 0;
#endif
}
@@ -1094,17 +1106,19 @@ static void rtc_dropped_irq(unsigned lon
return;
}

- /* Just in case someone disabled the timer from behind our back... */
- if (rtc_status & RTC_TIMER_ON)
- mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
-
rtc_irq_data += ((rtc_freq/HZ)<<8);
rtc_irq_data &= ~0xff;
rtc_irq_data |= (CMOS_READ(RTC_INTR_FLAGS) & 0xF0); /* restart */

freq = rtc_freq;

- spin_unlock_irq(&rtc_lock);
+ /* Just in case someone disabled the timer from behind our back... */
+ if (rtc_status & RTC_TIMER_ON) {
+ spin_unlock_irq(&rtc_lock);
+ mod_timer(&rtc_irq_timer, jiffies + HZ/rtc_freq + 2*HZ/100);
+ } else
+ spin_unlock_irq(&rtc_lock);
+

printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n", freq);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/