···380 struct clock_event_device *evt, int timer)381{382 u32 cnt;0383384 cnt = hpet_readl(HPET_COUNTER);385 cnt += (u32) delta;386 hpet_writel(cnt, HPET_Tn_CMP(timer));387388 /*389- * We need to read back the CMP register on certain HPET390- * implementations (ATI chipsets) which seem to delay the391- * transfer of the compare register into the internal compare392- * logic. With small deltas this might actually be too late as393- * the counter could already be higher than the compare value394- * at that point and we would wait for the next hpet interrupt395- * forever. We found out that reading the CMP register back396- * forces the transfer so we can rely on the comparison with397- * the counter register below. If the read back from the398- * compare register does not match the value we programmed399- * then we might have a real hardware problem. We can not do400- * much about it here, but at least alert the user/admin with401- * a prominent warning.402- *403- * An erratum on some chipsets (ICH9,..), results in404- * comparator read immediately following a write returning old405- * value. Workaround for this is to read this value second406- * time, when first read returns old value.407- *408- * In fact the write to the comparator register is delayed up409- * to two HPET cycles so the workaround we tried to restrict410- * the readback to those known to be borked ATI chipsets411- * failed miserably. So we give up on optimizations forever412- * and penalize all HPET incarnations unconditionally.413 */414- if (unlikely((u32)hpet_readl(HPET_Tn_CMP(timer)) != cnt)) {415- if (hpet_readl(HPET_Tn_CMP(timer)) != cnt)416- printk_once(KERN_WARNING417- "hpet: compare register read back failed.\n");418- }419420- return (s32)(hpet_readl(HPET_COUNTER) - cnt) >= 0 ? -ETIME : 0;421}422423static void hpet_legacy_set_mode(enum clock_event_mode mode,
···380 struct clock_event_device *evt, int timer)381{382 u32 cnt;383+ s32 res;384385 cnt = hpet_readl(HPET_COUNTER);386 cnt += (u32) delta;387 hpet_writel(cnt, HPET_Tn_CMP(timer));388389 /*390+ * HPETs are a complete disaster. The compare register is391+ * based on a equal comparison and neither provides a less392+ * than or equal functionality (which would require to take393+ * the wraparound into account) nor a simple count down event394+ * mode. Further the write to the comparator register is395+ * delayed internally up to two HPET clock cycles in certain396+ * chipsets (ATI, ICH9,10). We worked around that by reading397+ * back the compare register, but that required another398+ * workaround for ICH9,10 chips where the first readout after399+ * write can return the old stale value. We already have a400+ * minimum delta of 5us enforced, but a NMI or SMI hitting401+ * between the counter readout and the comparator write can402+ * move us behind that point easily. Now instead of reading403+ * the compare register back several times, we make the ETIME404+ * decision based on the following: Return ETIME if the405+ * counter value after the write is less than 8 HPET cycles406+ * away from the event or if the counter is already ahead of407+ * the event.000000408 */409+ res = (s32)(cnt - hpet_readl(HPET_COUNTER));0000410411+ return res < 8 ? -ETIME : 0;412}413414static void hpet_legacy_set_mode(enum clock_event_mode mode,