Skip to content

Commit a786ef1

Browse files
Daniel VacekKAGA-KOKO
authored andcommitted
x86/tsc: Make calibration refinement more robust
The threshold in tsc_read_refs() is constant which may favor slower CPUs but may not be optimal for simple reading of reference on faster ones. Hence make it proportional to tsc_khz when available to compensate for this. The threshold guards against any disturbance like IRQs, NMIs, SMIs or CPU stealing by host on guest systems so rename it accordingly and fix comments as well. Also on some systems there is noticeable DMI bus contention at some point during boot keeping the readout failing (observed with about one in ~300 boots when testing). In that case retry also the second readout instead of simply bailing out unrefined. Usually the next second the readout returns fast just fine without any issues. Signed-off-by: Daniel Vacek <neelx@redhat.com> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Borislav Petkov <bp@alien8.de> Cc: "H. Peter Anvin" <hpa@zytor.com> Link: https://lkml.kernel.org/r/1541437840-29293-1-git-send-email-neelx@redhat.com
1 parent 6510223 commit a786ef1

File tree

1 file changed

+16
-14
lines changed

1 file changed

+16
-14
lines changed

arch/x86/kernel/tsc.c

Lines changed: 16 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -297,15 +297,16 @@ static int __init tsc_setup(char *str)
297297

298298
__setup("tsc=", tsc_setup);
299299

300-
#define MAX_RETRIES 5
301-
#define SMI_TRESHOLD 50000
300+
#define MAX_RETRIES 5
301+
#define TSC_DEFAULT_THRESHOLD 0x20000
302302

303303
/*
304-
* Read TSC and the reference counters. Take care of SMI disturbance
304+
* Read TSC and the reference counters. Take care of any disturbances
305305
*/
306306
static u64 tsc_read_refs(u64 *p, int hpet)
307307
{
308308
u64 t1, t2;
309+
u64 thresh = tsc_khz ? tsc_khz >> 5 : TSC_DEFAULT_THRESHOLD;
309310
int i;
310311

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

747-
/* Check, whether the sampling was disturbed by an SMI */
748+
/* Check, whether the sampling was disturbed */
748749
if (tsc1 == ULLONG_MAX || tsc2 == ULLONG_MAX)
749750
continue;
750751

@@ -1268,7 +1269,7 @@ static DECLARE_DELAYED_WORK(tsc_irqwork, tsc_refine_calibration_work);
12681269
*/
12691270
static void tsc_refine_calibration_work(struct work_struct *work)
12701271
{
1271-
static u64 tsc_start = -1, ref_start;
1272+
static u64 tsc_start = ULLONG_MAX, ref_start;
12721273
static int hpet;
12731274
u64 tsc_stop, ref_stop, delta;
12741275
unsigned long freq;
@@ -1283,14 +1284,15 @@ static void tsc_refine_calibration_work(struct work_struct *work)
12831284
* delayed the first time we expire. So set the workqueue
12841285
* again once we know timers are working.
12851286
*/
1286-
if (tsc_start == -1) {
1287+
if (tsc_start == ULLONG_MAX) {
1288+
restart:
12871289
/*
12881290
* Only set hpet once, to avoid mixing hardware
12891291
* if the hpet becomes enabled later.
12901292
*/
12911293
hpet = is_hpet_enabled();
1292-
schedule_delayed_work(&tsc_irqwork, HZ);
12931294
tsc_start = tsc_read_refs(&ref_start, hpet);
1295+
schedule_delayed_work(&tsc_irqwork, HZ);
12941296
return;
12951297
}
12961298

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

1303-
/* Check, whether the sampling was disturbed by an SMI */
1304-
if (tsc_start == ULLONG_MAX || tsc_stop == ULLONG_MAX)
1305-
goto out;
1305+
/* Check, whether the sampling was disturbed */
1306+
if (tsc_stop == ULLONG_MAX)
1307+
goto restart;
13061308

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

0 commit comments

Comments
 (0)