Skip to content

Commit 3ad918e

Browse files
committed
Merge branch 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 timers updates from Thomas Gleixner: "This update contains: - The solution for the TSC deadline timer borkage, which is caused by a hardware problem in the TSC_ADJUST/TSC_DEADLINE_TIMER logic. The problem is documented now and fixed with a microcode update, so we can remove the workaround and just check for the microcode version. If the microcode is not up to date, then the TSC deadline timer is disabled. If the borkage is fixed by the proper microcode version, then the deadline timer can be used. In both cases the restrictions to the range of the TSC_ADJUST value, which were added as workarounds, are removed. - A few simple fixes and updates to the timer related x86 code" * 'x86-timers-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: x86/tsc: Call check_system_tsc_reliable() before unsynchronized_tsc() x86/hpet: Do not use smp_processor_id() in preemptible code x86/time: Make setup_default_timer_irq() static x86/tsc: Remove the TSC_ADJUST clamp x86/apic: Add TSC_DEADLINE quirk due to errata x86/apic: Change the lapic name in deadline mode
2 parents 8c07351 + a1272dd commit 3ad918e

File tree

6 files changed

+85
-25
lines changed

6 files changed

+85
-25
lines changed

arch/x86/include/asm/setup.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ extern unsigned long saved_video_mode;
4444

4545
extern void reserve_standard_io_resources(void);
4646
extern void i386_reserve_resources(void);
47-
extern void setup_default_timer_irq(void);
4847

4948
#ifdef CONFIG_X86_INTEL_MID
5049
extern void x86_intel_mid_early_setup(void);

arch/x86/kernel/apic/apic.c

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@
5454
#include <asm/mce.h>
5555
#include <asm/tsc.h>
5656
#include <asm/hypervisor.h>
57+
#include <asm/cpu_device_id.h>
58+
#include <asm/intel-family.h>
5759

5860
unsigned int num_processors;
5961

@@ -545,6 +547,81 @@ static struct clock_event_device lapic_clockevent = {
545547
};
546548
static DEFINE_PER_CPU(struct clock_event_device, lapic_events);
547549

550+
#define DEADLINE_MODEL_MATCH_FUNC(model, func) \
551+
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)&func }
552+
553+
#define DEADLINE_MODEL_MATCH_REV(model, rev) \
554+
{ X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, (unsigned long)rev }
555+
556+
static u32 hsx_deadline_rev(void)
557+
{
558+
switch (boot_cpu_data.x86_mask) {
559+
case 0x02: return 0x3a; /* EP */
560+
case 0x04: return 0x0f; /* EX */
561+
}
562+
563+
return ~0U;
564+
}
565+
566+
static u32 bdx_deadline_rev(void)
567+
{
568+
switch (boot_cpu_data.x86_mask) {
569+
case 0x02: return 0x00000011;
570+
case 0x03: return 0x0700000e;
571+
case 0x04: return 0x0f00000c;
572+
case 0x05: return 0x0e000003;
573+
}
574+
575+
return ~0U;
576+
}
577+
578+
static const struct x86_cpu_id deadline_match[] = {
579+
DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_HASWELL_X, hsx_deadline_rev),
580+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_X, 0x0b000020),
581+
DEADLINE_MODEL_MATCH_FUNC( INTEL_FAM6_BROADWELL_XEON_D, bdx_deadline_rev),
582+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_X, 0x02000014),
583+
584+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_CORE, 0x22),
585+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_ULT, 0x20),
586+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_HASWELL_GT3E, 0x17),
587+
588+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_CORE, 0x25),
589+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_BROADWELL_GT3E, 0x17),
590+
591+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_MOBILE, 0xb2),
592+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_SKYLAKE_DESKTOP, 0xb2),
593+
594+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_MOBILE, 0x52),
595+
DEADLINE_MODEL_MATCH_REV ( INTEL_FAM6_KABYLAKE_DESKTOP, 0x52),
596+
597+
{},
598+
};
599+
600+
static void apic_check_deadline_errata(void)
601+
{
602+
const struct x86_cpu_id *m = x86_match_cpu(deadline_match);
603+
u32 rev;
604+
605+
if (!m)
606+
return;
607+
608+
/*
609+
* Function pointers will have the MSB set due to address layout,
610+
* immediate revisions will not.
611+
*/
612+
if ((long)m->driver_data < 0)
613+
rev = ((u32 (*)(void))(m->driver_data))();
614+
else
615+
rev = (u32)m->driver_data;
616+
617+
if (boot_cpu_data.microcode >= rev)
618+
return;
619+
620+
setup_clear_cpu_cap(X86_FEATURE_TSC_DEADLINE_TIMER);
621+
pr_err(FW_BUG "TSC_DEADLINE disabled due to Errata; "
622+
"please update microcode to version: 0x%x (or later)\n", rev);
623+
}
624+
548625
/*
549626
* Setup the local APIC timer for this CPU. Copy the initialized values
550627
* of the boot CPU and register the clock event in the framework.
@@ -563,6 +640,7 @@ static void setup_APIC_timer(void)
563640
levt->cpumask = cpumask_of(smp_processor_id());
564641

565642
if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) {
643+
levt->name = "lapic-deadline";
566644
levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC |
567645
CLOCK_EVT_FEAT_DUMMY);
568646
levt->set_next_event = lapic_next_deadline;
@@ -1779,6 +1857,8 @@ void __init init_apic_mappings(void)
17791857
{
17801858
unsigned int new_apicid;
17811859

1860+
apic_check_deadline_errata();
1861+
17821862
if (x2apic_mode) {
17831863
boot_cpu_physical_apicid = read_apic_id();
17841864
return;

arch/x86/kernel/hpet.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ static void hpet_legacy_clockevent_register(void)
285285
* Start hpet with the boot cpu mask and make it
286286
* global after the IO_APIC has been initialized.
287287
*/
288-
hpet_clockevent.cpumask = cpumask_of(smp_processor_id());
288+
hpet_clockevent.cpumask = cpumask_of(boot_cpu_data.cpu_index);
289289
clockevents_config_and_register(&hpet_clockevent, hpet_freq,
290290
HPET_MIN_PROG_DELTA, 0x7FFFFFFF);
291291
global_clock_event = &hpet_clockevent;

arch/x86/kernel/time.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ static struct irqaction irq0 = {
6666
.name = "timer"
6767
};
6868

69-
void __init setup_default_timer_irq(void)
69+
static void __init setup_default_timer_irq(void)
7070
{
7171
if (!nr_legacy_irqs())
7272
return;

arch/x86/kernel/tsc.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1328,11 +1328,11 @@ void __init tsc_init(void)
13281328

13291329
use_tsc_delay();
13301330

1331+
check_system_tsc_reliable();
1332+
13311333
if (unsynchronized_tsc())
13321334
mark_tsc_unstable("TSCs unsynchronized");
13331335

1334-
check_system_tsc_reliable();
1335-
13361336
detect_art();
13371337
}
13381338

arch/x86/kernel/tsc_sync.c

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,8 @@ static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval,
7171
* non zero. We don't do that on non boot cpus because physical
7272
* hotplug should have set the ADJUST register to a value > 0 so
7373
* the TSC is in sync with the already running cpus.
74-
*
75-
* But we always force positive ADJUST values. Otherwise the TSC
76-
* deadline timer creates an interrupt storm. We also have to
77-
* prevent values > 0x7FFFFFFF as those wreckage the timer as well.
7874
*/
79-
if ((bootcpu && bootval != 0) || (!bootcpu && bootval < 0) ||
80-
(bootval > 0x7FFFFFFF)) {
75+
if (bootcpu && bootval != 0) {
8176
pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu,
8277
bootval);
8378
wrmsrl(MSR_IA32_TSC_ADJUST, 0);
@@ -451,20 +446,6 @@ void check_tsc_sync_target(void)
451446
*/
452447
cur->adjusted += cur_max_warp;
453448

454-
/*
455-
* TSC deadline timer stops working or creates an interrupt storm
456-
* with adjust values < 0 and > x07ffffff.
457-
*
458-
* To allow adjust values > 0x7FFFFFFF we need to disable the
459-
* deadline timer and use the local APIC timer, but that requires
460-
* more intrusive changes and we do not have any useful information
461-
* from Intel about the underlying HW wreckage yet.
462-
*/
463-
if (cur->adjusted < 0)
464-
cur->adjusted = 0;
465-
if (cur->adjusted > 0x7FFFFFFF)
466-
cur->adjusted = 0x7FFFFFFF;
467-
468449
pr_warn("TSC ADJUST compensate: CPU%u observed %lld warp. Adjust: %lld\n",
469450
cpu, cur_max_warp, cur->adjusted);
470451

0 commit comments

Comments
 (0)