2.6.33-longterm review patch. If anyone has any objections, please let us know.

------------------

From: Thomas Gleixner <tglx@linutronix.de>

(imported from commit v2.6.36-rc4-167-g995bd3b)

Due to the overly intelligent design of HPETs, we need to workaroundthe problem that the compare value which we write is already behindthe actual counter value at the point where the value hits the realcompare register. This happens for two reasons:

1) We read out the counter, add the delta and write the result to the compare register. When a NMI or SMI hits between the read out and the write then the counter can be ahead of the event already

2) The write to the compare register is delayed by up to two HPET cycles in certain chipsets.

We worked around this by reading back the compare register to makesure that the written value has hit the hardware. For certain ICH9+chipsets this can require two readouts, as the first one can returnthe previous compare register value. That's bad performance wise forthe normal case where the event is far enough in the future.

As we already know that the write can be delayed by up to two cycleswe can avoid the read back of the compare register completely if wemake the decision whether the delta has elapsed already or not basedon the following calculation:

cmp = event - actual_count;

If cmp is less than 8 HPET clock cycles, then we decide that the eventhas happened already and return -ETIME. That covers the above #1 and#2 problems which would cause a wait for HPET wraparound (~306seconds).

/*- * We need to read back the CMP register on certain HPET- * implementations (ATI chipsets) which seem to delay the- * transfer of the compare register into the internal compare- * logic. With small deltas this might actually be too late as- * the counter could already be higher than the compare value- * at that point and we would wait for the next hpet interrupt- * forever. We found out that reading the CMP register back- * forces the transfer so we can rely on the comparison with- * the counter register below. If the read back from the- * compare register does not match the value we programmed- * then we might have a real hardware problem. We can not do- * much about it here, but at least alert the user/admin with- * a prominent warning.- * An erratum on some chipsets (ICH9,..), results in comparator read- * immediately following a write returning old value. Workaround- * for this is to read this value second time, when first- * read returns old value.+ * HPETs are a complete disaster. The compare register is+ * based on a equal comparison and neither provides a less+ * than or equal functionality (which would require to take+ * the wraparound into account) nor a simple count down event+ * mode. Further the write to the comparator register is+ * delayed internally up to two HPET clock cycles in certain+ * chipsets (ATI, ICH9,10). We worked around that by reading+ * back the compare register, but that required another+ * workaround for ICH9,10 chips where the first readout after+ * write can return the old stale value. We already have a+ * minimum delta of 5us enforced, but a NMI or SMI hitting+ * between the counter readout and the comparator write can+ * move us behind that point easily. Now instead of reading+ * the compare register back several times, we make the ETIME+ * decision based on the following: Return ETIME if the+ * counter value after the write is less than 8 HPET cycles+ * away from the event or if the counter is already ahead of+ * the event. */- if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) {- WARN_ONCE(hpet_readl(HPET_Tn_CMP(timer)) != cnt,- KERN_WARNING "hpet: compare register read back failed.\n");- }+ res = (s32)(cnt - hpet_readl(HPET_COUNTER));