diff options
-rw-r--r-- | arch/x86/include/asm/setup.h | 1 | ||||
-rw-r--r-- | arch/x86/kernel/apic/apic.c | 80 | ||||
-rw-r--r-- | arch/x86/kernel/hpet.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/time.c | 2 | ||||
-rw-r--r-- | arch/x86/kernel/tsc.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/tsc_sync.c | 21 |
6 files changed, 85 insertions, 25 deletions
diff --git a/arch/x86/include/asm/setup.h b/arch/x86/include/asm/setup.h index ac1d5da14734..e4585a393965 100644 --- a/arch/x86/include/asm/setup.h +++ b/arch/x86/include/asm/setup.h | |||
@@ -44,7 +44,6 @@ extern unsigned long saved_video_mode; | |||
44 | 44 | ||
45 | extern void reserve_standard_io_resources(void); | 45 | extern void reserve_standard_io_resources(void); |
46 | extern void i386_reserve_resources(void); | 46 | extern void i386_reserve_resources(void); |
47 | extern void setup_default_timer_irq(void); | ||
48 | 47 | ||
49 | #ifdef CONFIG_X86_INTEL_MID | 48 | #ifdef CONFIG_X86_INTEL_MID |
50 | extern void x86_intel_mid_early_setup(void); | 49 | extern void x86_intel_mid_early_setup(void); |
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c index e7409468efc6..98b3dd8cf2bf 100644 --- a/arch/x86/kernel/apic/apic.c +++ b/arch/x86/kernel/apic/apic.c | |||
@@ -54,6 +54,8 @@ | |||
54 | #include <asm/mce.h> | 54 | #include <asm/mce.h> |
55 | #include <asm/tsc.h> | 55 | #include <asm/tsc.h> |
56 | #include <asm/hypervisor.h> | 56 | #include <asm/hypervisor.h> |
57 | #include <asm/cpu_device_id.h> | ||
58 | #include <asm/intel-family.h> | ||
57 | 59 | ||
58 | unsigned int num_processors; | 60 | unsigned int num_processors; |
59 | 61 | ||
@@ -545,6 +547,81 @@ static struct clock_event_device lapic_clockevent = { | |||
545 | }; | 547 | }; |
546 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); | 548 | static DEFINE_PER_CPU(struct clock_event_device, lapic_events); |
547 | 549 | ||
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 | |||
548 | /* | 625 | /* |
549 | * Setup the local APIC timer for this CPU. Copy the initialized values | 626 | * Setup the local APIC timer for this CPU. Copy the initialized values |
550 | * of the boot CPU and register the clock event in the framework. | 627 | * of the boot CPU and register the clock event in the framework. |
@@ -563,6 +640,7 @@ static void setup_APIC_timer(void) | |||
563 | levt->cpumask = cpumask_of(smp_processor_id()); | 640 | levt->cpumask = cpumask_of(smp_processor_id()); |
564 | 641 | ||
565 | if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { | 642 | if (this_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER)) { |
643 | levt->name = "lapic-deadline"; | ||
566 | levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | | 644 | levt->features &= ~(CLOCK_EVT_FEAT_PERIODIC | |
567 | CLOCK_EVT_FEAT_DUMMY); | 645 | CLOCK_EVT_FEAT_DUMMY); |
568 | levt->set_next_event = lapic_next_deadline; | 646 | levt->set_next_event = lapic_next_deadline; |
@@ -1779,6 +1857,8 @@ void __init init_apic_mappings(void) | |||
1779 | { | 1857 | { |
1780 | unsigned int new_apicid; | 1858 | unsigned int new_apicid; |
1781 | 1859 | ||
1860 | apic_check_deadline_errata(); | ||
1861 | |||
1782 | if (x2apic_mode) { | 1862 | if (x2apic_mode) { |
1783 | boot_cpu_physical_apicid = read_apic_id(); | 1863 | boot_cpu_physical_apicid = read_apic_id(); |
1784 | return; | 1864 | return; |
diff --git a/arch/x86/kernel/hpet.c b/arch/x86/kernel/hpet.c index 89ff7af2de50..16f82a3aaec7 100644 --- a/arch/x86/kernel/hpet.c +++ b/arch/x86/kernel/hpet.c | |||
@@ -285,7 +285,7 @@ static void hpet_legacy_clockevent_register(void) | |||
285 | * Start hpet with the boot cpu mask and make it | 285 | * Start hpet with the boot cpu mask and make it |
286 | * global after the IO_APIC has been initialized. | 286 | * global after the IO_APIC has been initialized. |
287 | */ | 287 | */ |
288 | hpet_clockevent.cpumask = cpumask_of(smp_processor_id()); | 288 | hpet_clockevent.cpumask = cpumask_of(boot_cpu_data.cpu_index); |
289 | clockevents_config_and_register(&hpet_clockevent, hpet_freq, | 289 | clockevents_config_and_register(&hpet_clockevent, hpet_freq, |
290 | HPET_MIN_PROG_DELTA, 0x7FFFFFFF); | 290 | HPET_MIN_PROG_DELTA, 0x7FFFFFFF); |
291 | global_clock_event = &hpet_clockevent; | 291 | global_clock_event = &hpet_clockevent; |
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c index d39c09119db6..e0754cdbad37 100644 --- a/arch/x86/kernel/time.c +++ b/arch/x86/kernel/time.c | |||
@@ -66,7 +66,7 @@ static struct irqaction irq0 = { | |||
66 | .name = "timer" | 66 | .name = "timer" |
67 | }; | 67 | }; |
68 | 68 | ||
69 | void __init setup_default_timer_irq(void) | 69 | static void __init setup_default_timer_irq(void) |
70 | { | 70 | { |
71 | if (!nr_legacy_irqs()) | 71 | if (!nr_legacy_irqs()) |
72 | return; | 72 | return; |
diff --git a/arch/x86/kernel/tsc.c b/arch/x86/kernel/tsc.c index 5270fc0c2df6..796d96bb0821 100644 --- a/arch/x86/kernel/tsc.c +++ b/arch/x86/kernel/tsc.c | |||
@@ -1328,11 +1328,11 @@ void __init tsc_init(void) | |||
1328 | 1328 | ||
1329 | use_tsc_delay(); | 1329 | use_tsc_delay(); |
1330 | 1330 | ||
1331 | check_system_tsc_reliable(); | ||
1332 | |||
1331 | if (unsynchronized_tsc()) | 1333 | if (unsynchronized_tsc()) |
1332 | mark_tsc_unstable("TSCs unsynchronized"); | 1334 | mark_tsc_unstable("TSCs unsynchronized"); |
1333 | 1335 | ||
1334 | check_system_tsc_reliable(); | ||
1335 | |||
1336 | detect_art(); | 1336 | detect_art(); |
1337 | } | 1337 | } |
1338 | 1338 | ||
diff --git a/arch/x86/kernel/tsc_sync.c b/arch/x86/kernel/tsc_sync.c index 728f75378475..7842371bc9e4 100644 --- a/arch/x86/kernel/tsc_sync.c +++ b/arch/x86/kernel/tsc_sync.c | |||
@@ -71,13 +71,8 @@ static void tsc_sanitize_first_cpu(struct tsc_adjust *cur, s64 bootval, | |||
71 | * non zero. We don't do that on non boot cpus because physical | 71 | * non zero. We don't do that on non boot cpus because physical |
72 | * hotplug should have set the ADJUST register to a value > 0 so | 72 | * hotplug should have set the ADJUST register to a value > 0 so |
73 | * the TSC is in sync with the already running cpus. | 73 | * 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. | ||
78 | */ | 74 | */ |
79 | if ((bootcpu && bootval != 0) || (!bootcpu && bootval < 0) || | 75 | if (bootcpu && bootval != 0) { |
80 | (bootval > 0x7FFFFFFF)) { | ||
81 | pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu, | 76 | pr_warn(FW_BUG "TSC ADJUST: CPU%u: %lld force to 0\n", cpu, |
82 | bootval); | 77 | bootval); |
83 | wrmsrl(MSR_IA32_TSC_ADJUST, 0); | 78 | wrmsrl(MSR_IA32_TSC_ADJUST, 0); |
@@ -451,20 +446,6 @@ retry: | |||
451 | */ | 446 | */ |
452 | cur->adjusted += cur_max_warp; | 447 | cur->adjusted += cur_max_warp; |
453 | 448 | ||
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 | |||
468 | pr_warn("TSC ADJUST compensate: CPU%u observed %lld warp. Adjust: %lld\n", | 449 | pr_warn("TSC ADJUST compensate: CPU%u observed %lld warp. Adjust: %lld\n", |
469 | cpu, cur_max_warp, cur->adjusted); | 450 | cpu, cur_max_warp, cur->adjusted); |
470 | 451 | ||