Commit 211baf4f authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'x86-timers-for-linus' of...

Merge branch 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  x86: Hpet: Avoid the comparator readback penalty
parents c19483cc 995bd3bb
...@@ -380,44 +380,35 @@ static int hpet_next_event(unsigned long delta, ...@@ -380,44 +380,35 @@ static int hpet_next_event(unsigned long delta,
struct clock_event_device *evt, int timer) struct clock_event_device *evt, int timer)
{ {
u32 cnt; u32 cnt;
s32 res;
cnt = hpet_readl(HPET_COUNTER); cnt = hpet_readl(HPET_COUNTER);
cnt += (u32) delta; cnt += (u32) delta;
hpet_writel(cnt, HPET_Tn_CMP(timer)); hpet_writel(cnt, HPET_Tn_CMP(timer));
/* /*
* We need to read back the CMP register on certain HPET * HPETs are a complete disaster. The compare register is
* implementations (ATI chipsets) which seem to delay the * based on a equal comparison and neither provides a less
* transfer of the compare register into the internal compare * than or equal functionality (which would require to take
* logic. With small deltas this might actually be too late as * the wraparound into account) nor a simple count down event
* the counter could already be higher than the compare value * mode. Further the write to the comparator register is
* at that point and we would wait for the next hpet interrupt * delayed internally up to two HPET clock cycles in certain
* forever. We found out that reading the CMP register back * chipsets (ATI, ICH9,10). We worked around that by reading
* forces the transfer so we can rely on the comparison with * back the compare register, but that required another
* the counter register below. If the read back from the * workaround for ICH9,10 chips where the first readout after
* compare register does not match the value we programmed * write can return the old stale value. We already have a
* then we might have a real hardware problem. We can not do * minimum delta of 5us enforced, but a NMI or SMI hitting
* much about it here, but at least alert the user/admin with * between the counter readout and the comparator write can
* a prominent warning. * move us behind that point easily. Now instead of reading
* * the compare register back several times, we make the ETIME
* An erratum on some chipsets (ICH9,..), results in * decision based on the following: Return ETIME if the
* comparator read immediately following a write returning old * counter value after the write is less than 8 HPET cycles
* value. Workaround for this is to read this value second * away from the event or if the counter is already ahead of
* time, when first read returns old value. * the event.
*
* In fact the write to the comparator register is delayed up
* to two HPET cycles so the workaround we tried to restrict
* the readback to those known to be borked ATI chipsets
* failed miserably. So we give up on optimizations forever
* and penalize all HPET incarnations unconditionally.
*/ */
if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) { res = (s32)(cnt - hpet_readl(HPET_COUNTER));
if (hpet_readl(HPET_Tn_CMP(timer)) != cnt)
printk_once(KERN_WARNING
"hpet: compare register read back failed.\n");
}
return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0; return res < 8 ? -ETIME : 0;
} }
static void hpet_legacy_set_mode(enum clock_event_mode mode, static void hpet_legacy_set_mode(enum clock_event_mode mode,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment