Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 351e1aa6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

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

Pull x86 timer fixes from Thomas Gleixner:
 "Two commits which were missed to be sent during the merge window.

   - The TSC calibration fix turns out to be more urgent as recent
     Skylake-X systems seem to have massive trouble with calibration
     disturbance. This should go back into stable for that reason and it
     the risk of breakage is rather low.

   - Drop an unused define"

* 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/hpet: Remove unused FSEC_PER_NSEC define
  x86/tsc: Make calibration refinement more robust
parents f907bb4c d999c0ec
Loading
Loading
Loading
Loading
+0 −4
Original line number Diff line number Diff line
@@ -21,10 +21,6 @@

#define HPET_MASK			CLOCKSOURCE_MASK(32)

/* FSEC = 10^-15
   NSEC = 10^-9 */
#define FSEC_PER_NSEC			1000000L

#define HPET_DEV_USED_BIT		2
#define HPET_DEV_USED			(1 << HPET_DEV_USED_BIT)
#define HPET_DEV_VALID			0x8
+16 −14
Original line number Diff line number Diff line
@@ -298,14 +298,15 @@ static int __init tsc_setup(char *str)
__setup("tsc=", tsc_setup);

#define MAX_RETRIES		5
#define SMI_TRESHOLD    50000
#define TSC_DEFAULT_THRESHOLD	0x20000

/*
 * Read TSC and the reference counters. Take care of SMI disturbance
 * Read TSC and the reference counters. Take care of any disturbances
 */
static u64 tsc_read_refs(u64 *p, int hpet)
{
	u64 t1, t2;
	u64 thresh = tsc_khz ? tsc_khz >> 5 : TSC_DEFAULT_THRESHOLD;
	int i;

	for (i = 0; i < MAX_RETRIES; i++) {
@@ -315,7 +316,7 @@ static u64 tsc_read_refs(u64 *p, int hpet)
		else
			*p = acpi_pm_read_early();
		t2 = get_cycles();
		if ((t2 - t1) < SMI_TRESHOLD)
		if ((t2 - t1) < thresh)
			return t2;
	}
	return ULLONG_MAX;
@@ -703,15 +704,15 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void)
	 * zero. In each wait loop iteration we read the TSC and check
	 * the delta to the previous read. We keep track of the min
	 * and max values of that delta. The delta is mostly defined
	 * by the IO time of the PIT access, so we can detect when a
	 * SMI/SMM disturbance happened between the two reads. If the
	 * by the IO time of the PIT access, so we can detect when
	 * any disturbance happened between the two reads. If the
	 * maximum time is significantly larger than the minimum time,
	 * then we discard the result and have another try.
	 *
	 * 2) Reference counter. If available we use the HPET or the
	 * PMTIMER as a reference to check the sanity of that value.
	 * We use separate TSC readouts and check inside of the
	 * reference read for a SMI/SMM disturbance. We dicard
	 * reference read for any possible disturbance. We dicard
	 * disturbed values here as well. We do that around the PIT
	 * calibration delay loop as we have to wait for a certain
	 * amount of time anyway.
@@ -744,7 +745,7 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void)
		if (ref1 == ref2)
			continue;

		/* Check, whether the sampling was disturbed by an SMI */
		/* Check, whether the sampling was disturbed */
		if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX)
			continue;

@@ -1268,7 +1269,7 @@ static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
 */
static void tsc_refine_calibration_work(struct work_struct *work)
{
	static u64 tsc_start = -1, ref_start;
	static u64 tsc_start = ULLONG_MAX, ref_start;
	static int hpet;
	u64 tsc_stop, ref_stop, delta;
	unsigned long freq;
@@ -1283,14 +1284,15 @@ static void tsc_refine_calibration_work(struct work_struct *work)
	 * delayed the first time we expire. So set the workqueue
	 * again once we know timers are working.
	 */
	if (tsc_start == -1) {
	if (tsc_start == ULLONG_MAX) {
restart:
		/*
		 * Only set hpet once, to avoid mixing hardware
		 * if the hpet becomes enabled later.
		 */
		hpet = is_hpet_enabled();
		schedule_delayed_work(&tsc_irqwork, HZ);
		tsc_start = tsc_read_refs(&ref_start, hpet);
		schedule_delayed_work(&tsc_irqwork, HZ);
		return;
	}

@@ -1300,9 +1302,9 @@ static void tsc_refine_calibration_work(struct work_struct *work)
	if (ref_start == ref_stop)
		goto out;

	/* Check, whether the sampling was disturbed by an SMI */
	if (tsc_start == ULLONG_MAX || tsc_stop == ULLONG_MAX)
		goto out;
	/* Check, whether the sampling was disturbed */
	if (tsc_stop == ULLONG_MAX)
		goto restart;

	delta = tsc_stop - tsc_start;
	delta *= 1000000LL;