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
This commit is contained in:
commit
351e1aa6cb
|
@ -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
|
||||
|
|
|
@ -297,15 +297,16 @@ static int __init tsc_setup(char *str)
|
|||
|
||||
__setup("tsc=", tsc_setup);
|
||||
|
||||
#define MAX_RETRIES 5
|
||||
#define SMI_TRESHOLD 50000
|
||||
#define MAX_RETRIES 5
|
||||
#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;
|
||||
|
|
Loading…
Reference in New Issue
Block a user