|
@@ -1148,23 +1148,25 @@ int hpet_rtc_timer_init(void)
|
|
|
hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
|
|
|
|
|
|
local_irq_save(flags);
|
|
|
+
|
|
|
cnt = hpet_readl(HPET_COUNTER);
|
|
|
cnt += ((hpet_tick*HZ)/hpet_rtc_int_freq);
|
|
|
hpet_writel(cnt, HPET_T1_CMP);
|
|
|
hpet_t1_cmp = cnt;
|
|
|
- local_irq_restore(flags);
|
|
|
|
|
|
cfg = hpet_readl(HPET_T1_CFG);
|
|
|
cfg &= ~HPET_TN_PERIODIC;
|
|
|
cfg |= HPET_TN_ENABLE | HPET_TN_32BIT;
|
|
|
hpet_writel(cfg, HPET_T1_CFG);
|
|
|
|
|
|
+ local_irq_restore(flags);
|
|
|
+
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
|
static void hpet_rtc_timer_reinit(void)
|
|
|
{
|
|
|
- unsigned int cfg, cnt;
|
|
|
+ unsigned int cfg, cnt, ticks_per_int, lost_ints;
|
|
|
|
|
|
if (unlikely(!(PIE_on | AIE_on | UIE_on))) {
|
|
|
cfg = hpet_readl(HPET_T1_CFG);
|
|
@@ -1179,10 +1181,33 @@ static void hpet_rtc_timer_reinit(void)
|
|
|
hpet_rtc_int_freq = DEFAULT_RTC_INT_FREQ;
|
|
|
|
|
|
/* It is more accurate to use the comparator value than current count.*/
|
|
|
- cnt = hpet_t1_cmp;
|
|
|
- cnt += hpet_tick*HZ/hpet_rtc_int_freq;
|
|
|
- hpet_writel(cnt, HPET_T1_CMP);
|
|
|
- hpet_t1_cmp = cnt;
|
|
|
+ ticks_per_int = hpet_tick * HZ / hpet_rtc_int_freq;
|
|
|
+ hpet_t1_cmp += ticks_per_int;
|
|
|
+ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * If the interrupt handler was delayed too long, the write above tries
|
|
|
+ * to schedule the next interrupt in the past and the hardware would
|
|
|
+ * not interrupt until the counter had wrapped around.
|
|
|
+ * So we have to check that the comparator wasn't set to a past time.
|
|
|
+ */
|
|
|
+ cnt = hpet_readl(HPET_COUNTER);
|
|
|
+ if (unlikely((int)(cnt - hpet_t1_cmp) > 0)) {
|
|
|
+ lost_ints = (cnt - hpet_t1_cmp) / ticks_per_int + 1;
|
|
|
+ /* Make sure that, even with the time needed to execute
|
|
|
+ * this code, the next scheduled interrupt has been moved
|
|
|
+ * back to the future: */
|
|
|
+ lost_ints++;
|
|
|
+
|
|
|
+ hpet_t1_cmp += lost_ints * ticks_per_int;
|
|
|
+ hpet_writel(hpet_t1_cmp, HPET_T1_CMP);
|
|
|
+
|
|
|
+ if (PIE_on)
|
|
|
+ PIE_count += lost_ints;
|
|
|
+
|
|
|
+ printk(KERN_WARNING "rtc: lost some interrupts at %ldHz.\n",
|
|
|
+ hpet_rtc_int_freq);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
/*
|