Commit f1c18071ad70e2a78ab31fc26a18fcfa954a05c6

Authored by Thomas Gleixner
1 parent 4720dd1b38

x86: HPET: Chose a paranoid safe value for the ETIME check

commit 995bd3bb5 (x86: Hpet: Avoid the comparator readback penalty)
chose 8 HPET cycles as a safe value for the ETIME check, as we had the
confirmation that the posted write to the comparator register is
delayed by two HPET clock cycles on Intel chipsets which showed
readback problems.

After that patch hit mainline we got reports from machines with newer
AMD chipsets which seem to have an even longer delay. See
http://thread.gmane.org/gmane.linux.kernel/1054283 and
http://thread.gmane.org/gmane.linux.kernel/1069458 for further
information.

Boris tried to come up with an ACPI based selection of the minimum
HPET cycles, but this failed on a couple of test machines. And of
course we did not get any useful information from the hardware folks.

For now our only option is to chose a paranoid high and safe value for
the minimum HPET cycles used by the ETIME check. Adjust the minimum ns
value for the HPET clockevent accordingly.

Reported-Bistected-and-Tested-by: Markus Trippelsdorf <markus@trippelsdorf.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
LKML-Reference: <alpine.LFD.2.00.1012131222420.2653@localhost6.localdomain6>
Cc: Simon Kirby <sim@hostway.ca>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Andreas Herrmann <Andreas.Herrmann3@amd.com>
Cc: John Stultz <johnstul@us.ibm.com>

Showing 1 changed file with 16 additions and 10 deletions Side-by-side Diff

arch/x86/kernel/hpet.c
... ... @@ -27,6 +27,9 @@
27 27 #define HPET_DEV_FSB_CAP 0x1000
28 28 #define HPET_DEV_PERI_CAP 0x2000
29 29  
  30 +#define HPET_MIN_CYCLES 128
  31 +#define HPET_MIN_PROG_DELTA (HPET_MIN_CYCLES + (HPET_MIN_CYCLES >> 1))
  32 +
30 33 #define EVT_TO_HPET_DEV(evt) container_of(evt, struct hpet_dev, evt)
31 34  
32 35 /*
... ... @@ -299,8 +302,9 @@
299 302 /* Calculate the min / max delta */
300 303 hpet_clockevent.max_delta_ns = clockevent_delta2ns(0x7FFFFFFF,
301 304 &hpet_clockevent);
302   - /* 5 usec minimum reprogramming delta. */
303   - hpet_clockevent.min_delta_ns = 5000;
  305 + /* Setup minimum reprogramming delta. */
  306 + hpet_clockevent.min_delta_ns = clockevent_delta2ns(HPET_MIN_PROG_DELTA,
  307 + &hpet_clockevent);
304 308  
305 309 /*
306 310 * Start hpet with the boot cpu mask and make it
307 311  
308 312  
309 313  
... ... @@ -393,22 +397,24 @@
393 397 * the wraparound into account) nor a simple count down event
394 398 * mode. Further the write to the comparator register is
395 399 * delayed internally up to two HPET clock cycles in certain
396   - * chipsets (ATI, ICH9,10). We worked around that by reading
397   - * back the compare register, but that required another
398   - * workaround for ICH9,10 chips where the first readout after
399   - * write can return the old stale value. We already have a
400   - * minimum delta of 5us enforced, but a NMI or SMI hitting
  400 + * chipsets (ATI, ICH9,10). Some newer AMD chipsets have even
  401 + * longer delays. We worked around that by reading back the
  402 + * compare register, but that required another workaround for
  403 + * ICH9,10 chips where the first readout after write can
  404 + * return the old stale value. We already had a minimum
  405 + * programming delta of 5us enforced, but a NMI or SMI hitting
401 406 * between the counter readout and the comparator write can
402 407 * move us behind that point easily. Now instead of reading
403 408 * the compare register back several times, we make the ETIME
404 409 * decision based on the following: Return ETIME if the
405   - * counter value after the write is less than 8 HPET cycles
  410 + * counter value after the write is less than HPET_MIN_CYCLES
406 411 * away from the event or if the counter is already ahead of
407   - * the event.
  412 + * the event. The minimum programming delta for the generic
  413 + * clockevents code is set to 1.5 * HPET_MIN_CYCLES.
408 414 */
409 415 res = (s32)(cnt - hpet_readl(HPET_COUNTER));
410 416  
411   - return res < 8 ? -ETIME : 0;
  417 + return res < HPET_MIN_CYCLES ? -ETIME : 0;
412 418 }
413 419  
414 420 static void hpet_legacy_set_mode(enum clock_event_mode mode,