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

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
...@@ -21,10 +21,6 @@ ...@@ -21,10 +21,6 @@
#define HPET_MASK CLOCKSOURCE_MASK(32) #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_BIT 2
#define HPET_DEV_USED (1 << HPET_DEV_USED_BIT) #define HPET_DEV_USED (1 << HPET_DEV_USED_BIT)
#define HPET_DEV_VALID 0x8 #define HPET_DEV_VALID 0x8
......
...@@ -297,15 +297,16 @@ static int __init tsc_setup(char *str) ...@@ -297,15 +297,16 @@ static int __init tsc_setup(char *str)
__setup("tsc=", tsc_setup); __setup("tsc=", tsc_setup);
#define MAX_RETRIES 5 #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) static u64 tsc_read_refs(u64 *p, int hpet)
{ {
u64 t1, t2; u64 t1, t2;
u64 thresh = tsc_khz ? tsc_khz >> 5 : TSC_DEFAULT_THRESHOLD;
int i; int i;
for (i = 0; i < MAX_RETRIES; i++) { for (i = 0; i < MAX_RETRIES; i++) {
...@@ -315,7 +316,7 @@ static u64 tsc_read_refs(u64 *p, int hpet) ...@@ -315,7 +316,7 @@ static u64 tsc_read_refs(u64 *p, int hpet)
else else
*p = acpi_pm_read_early(); *p = acpi_pm_read_early();
t2 = get_cycles(); t2 = get_cycles();
if ((t2 - t1) < SMI_TRESHOLD) if ((t2 - t1) < thresh)
return t2; return t2;
} }
return ULLONG_MAX; return ULLONG_MAX;
...@@ -703,15 +704,15 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void) ...@@ -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 * zero. In each wait loop iteration we read the TSC and check
* the delta to the previous read. We keep track of the min * the delta to the previous read. We keep track of the min
* and max values of that delta. The delta is mostly defined * 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 * by the IO time of the PIT access, so we can detect when
* SMI/SMM disturbance happened between the two reads. If the * any disturbance happened between the two reads. If the
* maximum time is significantly larger than the minimum time, * maximum time is significantly larger than the minimum time,
* then we discard the result and have another try. * then we discard the result and have another try.
* *
* 2) Reference counter. If available we use the HPET or the * 2) Reference counter. If available we use the HPET or the
* PMTIMER as a reference to check the sanity of that value. * PMTIMER as a reference to check the sanity of that value.
* We use separate TSC readouts and check inside of the * 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 * disturbed values here as well. We do that around the PIT
* calibration delay loop as we have to wait for a certain * calibration delay loop as we have to wait for a certain
* amount of time anyway. * amount of time anyway.
...@@ -744,7 +745,7 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void) ...@@ -744,7 +745,7 @@ static unsigned long pit_hpet_ptimer_calibrate_cpu(void)
if (ref1 == ref2) if (ref1 == ref2)
continue; continue;
/* Check, whether the sampling was disturbed by an SMI */ /* Check, whether the sampling was disturbed */
if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX) if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX)
continue; continue;
...@@ -1268,7 +1269,7 @@ static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work); ...@@ -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 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; static int hpet;
u64 tsc_stop, ref_stop, delta; u64 tsc_stop, ref_stop, delta;
unsigned long freq; unsigned long freq;
...@@ -1283,14 +1284,15 @@ static void tsc_refine_calibration_work(struct work_struct *work) ...@@ -1283,14 +1284,15 @@ static void tsc_refine_calibration_work(struct work_struct *work)
* delayed the first time we expire. So set the workqueue * delayed the first time we expire. So set the workqueue
* again once we know timers are working. * 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 * Only set hpet once, to avoid mixing hardware
* if the hpet becomes enabled later. * if the hpet becomes enabled later.
*/ */
hpet = is_hpet_enabled(); hpet = is_hpet_enabled();
schedule_delayed_work(&tsc_irqwork, HZ);
tsc_start = tsc_read_refs(&ref_start, hpet); tsc_start = tsc_read_refs(&ref_start, hpet);
schedule_delayed_work(&tsc_irqwork, HZ);
return; return;
} }
...@@ -1300,9 +1302,9 @@ static void tsc_refine_calibration_work(struct work_struct *work) ...@@ -1300,9 +1302,9 @@ static void tsc_refine_calibration_work(struct work_struct *work)
if (ref_start == ref_stop) if (ref_start == ref_stop)
goto out; goto out;
/* Check, whether the sampling was disturbed by an SMI */ /* Check, whether the sampling was disturbed */
if (tsc_start == ULLONG_MAX || tsc_stop == ULLONG_MAX) if (tsc_stop == ULLONG_MAX)
goto out; goto restart;
delta = tsc_stop - tsc_start; delta = tsc_stop - tsc_start;
delta *= 1000000LL; delta *= 1000000LL;
......
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